Анімація шляхів по колу з допомогою CSS3

1

Від автора: Довгий час я вважав, що не можна застосовувати CSS Transitions або анімацію для пересування об’єктів DOM яким-небудь іншим чином, крім руху по прямій. Звичайно, розробник міг би застосувати безліч ключових кадрів для створення списку прямих шляхів і симулювати криву, але не думав, що можна визначити криву за допомогою всього двох ключових кадрів або простого CSS transition. Я помилявся.

Анімація шляхів по колу з допомогою CSS3

Вищенаведений приклад анімована за допомогою всього двох ключових кадрів анімації CSS3! Хоча ви могли застосувати для цього jQuery.animate() або requestAnimationFrame, краще взяти CSS3 замість JavaScript’а — отримана анімація завжди буде гарантовано гладше (особливо на мобільних пристроях) плюс може заощадити енергію батареї. У даній статті наведено рецепт CSS виконання цього трюку у всіх браузерах з підтримкою анімацією CSS3 з ретельним описом застосованої математики, а також альтернативний варіант для старих версій IE, не підтримують анімацію CSS3.

Дайте мені CSS!

Єдина причина, чому CSS тут такий довгий – повторення коду префікса для браузерів:

.saturn {
/*
* Зробіть вихідне положення центром окружності, по якій повинен
* рухатися об’єкт.
*/
position: absolute;
left: 315px;
top: 143px;
/*
* Встановлює тривалість анімації, розрахунок часу (чи ослаблення) і підрахунок повторень. Переконайтеся, що застосовуєте відповідні префікси, а також офіційний синтаксис. Пам’ятайте, такі інструменти як CSS Please допоможуть вам у цьому!
*/
-webkit-animation: myOrbit 4s linear infinite; /* Chrome, Safari 5 */
-moz-animation: myOrbit 4s linear infinite; /* Firefox 5-15 */
-o-animation: myOrbit 4s linear infinite; /* Opera 12+ */
animation: myOrbit 4s linear infinite; /* Chrome, Firefox 16+,
IE 10+, Safari 5 */
}
/*
* Встановіть ключові кадри, щоб ті в дійсності описували початкове і кінцеве стану анімації. Браузер інтерполює всі кадри між цими точками. І знову пам’ятайте про префіксах!
*/
@-webkit-keyframes myOrbit {
from { -webkit-transform: rotate(0deg) translateX(150px) rotate(0deg); }
to { -webkit-transform: rotate(360deg) translateX(150px) rotate(-360deg); }
}
@-moz-keyframes myOrbit {
from { -moz-transform: rotate(0deg) translateX(150px) rotate(0deg); }
to { -moz-transform: rotate(360deg) translateX(150px) rotate(-360deg); }
}
@-o-keyframes myOrbit {
from { -o-transform: rotate(0deg) translateX(150px) rotate(0deg); }
to { -o-transform: rotate(360deg) translateX(150px) rotate(-360deg); }
}
@keyframes myOrbit {
from { transform: rotate(0deg) translateX(150px) rotate(0deg); }
to { transform: rotate(360deg) translateX(150px) rotate(-360deg); }
}

Найцікавіший ділянку коду– це ключовий внизу. Значення translateX() повинне бути дорівнює радіусу кола (тобто діаметру, поделенному на два). Функції rotate() у правилах повинні бути встановлені на початковий і кінцевий кути анімації. Зверніть увагу, що тут два виклику rotate() — другий повинен бути від’ємним значенням першого.

Як же все це працює?

Щоб зрозуміти, чому це працює, дозвольте мені покроково пояснити математику, генеруючу кадр, де Сатурн обернувся на 45 градусів навколо Сонця. Від цієї точки ми розглянемо, як це застосовується до повної анімації.

Крок 1: Помістіть об’єкт в центр

Помістіть об’єкт в центр кола, по якій він повинен рухатися. У вищенаведеному прикладі Сонце (яке є всього лише анімованим GIF’ом) знаходиться в центрі, так що передвинем Сатурн так, щоб той був прямо на ньому:

Анімація шляхів по колу з допомогою CSS3

.saturn {
left: 315px;
position: absolute;
top: 143px;
}

Крок 2: Використовуйте translateX() для визначення радіусу кола

Далі нам потрібно пересунути об’єкт на край колу. Для цього прикладу діаметр окружності становить, скажімо, 300px. Ми встановлюємо властивість CSS3 transform на transformX(150px) (де 150px – половина від 300px).

Анімація шляхів по колу з допомогою CSS3

.saturn {
left: 315px;
position: absolute;
top: 143px;
/* Примітка: Заради стислості я опустив код префікса */
transform: translateX(150px);
}

Крок 3: Вставити сюди в один або два rotate().

Якщо в transform властивість вставити rotate() перед translateX(), то можна використовувати його для управління шляхом по колу. Щоб продемонструвати це, давайте вставимо один з 45deg:

Анімація шляхів по колу з допомогою CSS3

.saturn {
left: 315px;
position: absolute;
top: 143px;
/* Примітка: Заради стислості я опустив код префікса */
transform: rotate(45deg) translateX(150px);
}
[CSS]

Проблема полягає в тому, що на вищенаведеній анімації Сатурн не повинен обертатися з власної осі. Тому нам потрібно додати rotate(-45deg) після translateX() для обертання Сатурна назад у «вертикальному» положенні:

Анімація шляхів по колу з допомогою CSS3
[CSS]
.saturn {
left: 315px;
position: absolute;
top: 143px;
/* Примітка: Заради стислості я опустив код вендорного префікса */
transform: rotate(45deg) translateX(150px) rotate(-45deg);
}

Крок 4: Застосуйте код анімації

Тепер для завершення роботи давайте застосуємо стилі анімації. Нам потрібно, щоб Сатурн обертається навколо Сонця за 2 seconds, тому додаємо підходящий CSS для визначення швидкості, довжини і ослаблення нашої анімації:

#saturn {
left: 315px;
position: absolute;
top: 143px;
/*
* CSS Please допоможе вам гарантувати кросбраузерність синтаксис
*/
-webkit-animation: orbit2 4s linear infinite; /* Chrome, Safari 5 */
-moz-animation: orbit2 4s linear infinite; /* Firefox 5-15 */
-o-animation: orbit2 4s linear infinite; /* Opera 12+ */
animation: orbit2 4s linear infinite; /* Chrome, Firefox 16+,
IE 10+, Safari 5 */
}

Потім додаємо ключові кадри в CSS, щоб сказати браузеру, що анімація повинна обертатися навколо Сонця (тобто від 0 до 360 градусів):

@-webkit-keyframes orbit2 {
from { -webkit-transform: rotate(0deg) translateX(150px) rotate(0deg); }
to { -webkit-transform: rotate(360deg) translateX(150px) rotate(-360deg); }
}
@-moz-keyframes orbit2 {
from { -moz-transform: rotate(0deg) translateX(150px) rotate(0deg); }
to { -moz-transform: rotate(360deg) translateX(150px) rotate(-360deg); }
}
@-o-keyframes orbit2 {
from { -o-transform: rotate(0deg) translateX(150px) rotate(0deg); }
to { -o-transform: rotate(360deg) translateX(150px) rotate(-360deg); }
}
@keyframes orbit2 {
from { transform: rotate(0deg) translateX(150px) rotate(0deg); }
to { transform: rotate(360deg) translateX(150px) rotate(-360deg); }
}

Ось так! Ми закінчили. Плесніть собі мартіні — ви його заслужили!

Погляньте на результат

Що щодо IE?

IE10 – єдина різновид Internet explorer’а, що підтримує анімацію CSS3. Оскільки в диких місцях IE7 і 8 все ще широко застосовуються, було б добре використовувати якусь альтернативу. Застосовуючи умовні коментарі, ви могли б включити JavaScript, призначений тільки для IE, який зробив би це для вас за допомогою jQuery.aniamte() або requestAnimationFrame() Підлоги Айриша (Paul Irish). Так як більша частина пристроїв, ймовірно, все одно використовує jQuery, вищенаведений приклад використовує цей код для створення анімації в IE. Робить він це, включаючи код JS виключно для IE:

Example of Using CSS3 Animations and Circular Paths.

(Зверніть увагу на умовні коментарі для IE9 і нижче!) transition-circle-ie.js містить код, який робить анімацію за допомогою jquery.animate():

var ieRotate = new function () {
var me = this,
$saturn,
initialPosition,
radius = 150;
/*
* Тут ініціалізувати анімацію.
*/
me.init = function () {
// Кешує об’єкт jQuery в цілях продуктивності.
$saturn = $(‘#saturn’);
// Зберігає первісне розташування Сатурна. Застосовується пізніше при розрахунку
// анімації орбіти.
initialPosition = {
x: parseInt($saturn.css(‘left’)),
y: parseInt($saturn.css(‘top’))
};
// Починає анімацію.
rotateOnce();
}
function rotateOnce() {
/*
* jQuery.animate() було створено для анімації об’єктів DOM шляхом вставки проміжних кадрів цифрових значень властивостей CSS. Воно добре для переміщення цих об’єктів DOM по прямих лініях, але не так добре при спробі зрушити об’єкт по колу. Тут показано, як можна обійти це обмеження.
*/
// Крок 1: Встановіть властивість моделі на кут вихідної позиції
// Сатурна. Ми використовуємо text-indent, так як воно нічого не робить
// з зображенням.
$saturn.css(‘text-indent’, 0);
// Крок 2: Ми встановлюємо jQuery.animate() для анімації за допомогою….
$saturn.animate(
// … спочатку встановлюючи остаточне значення text-indent на 2*π
// радиана, що по суті означає 360 градусів …
{
‘text-indent’: 2*Math.PI
}, {
/*
* … далі ми встановлюємо функцію кроку step, яка стане генерувати кадр при вугіллі, збережених у властивості text-indent в цій окремій частині анімації. Формули, що застосовуються для координат x і y, отримані з допомогою полярного рівняння окружності.
*/
step: function (now) {
$saturn.css(‘left’, initialPosition.x + radius * Math.cos(now))
.css(‘top’, initialPosition.y + radius * Math.sin(now))
},
// Так встановлюється тривалість анімації в 4000 мілісекунд (= 4 секунди)
duration: 4000,
// Властивість easing аналогічно функції CSS3
// animation-timing-funciton
easing: ‘linear’,
// По закінченні анімації ми знову викликаємо rotateOnce(), так
// що анімація повторюється.
complete: rotateOnce
}
);
}
}
$(document).ready(ieRotate.init);

Погляньте на докладні коментарі того, як працює код. У JavaScript’е використовуються радіани замість градусів при розрахунку значень sin() і cos() — якщо ви не знайомі з радіанами, на PurpleMath є стаття, яка вам допоможе.

Погляньте на результат

Варіації цієї техніки

А якби замість планети, скажімо, вам потрібен був космічний корабель, що обертається навколо Сонця. Ось «класичний» приклад:

Анімація шляхів по колу з допомогою CSS3

Зверніть увагу, що корабель завжди дивиться в ту сторону, в яку летить. Це можна зробити з тим же CSS, що й вище, за винятком того, що ви видалили б другу rotate() властивості transform:

/*
* Код префікса вилучений для стислості.
*/
#saturn {
left: 315px;
position: absolute;
top: 143px;
/* Встановіть анімацію */
animation: orbit 20s linear infinite;
}
/* Зверніть увагу, що друга rotate в кожній з трансформацій нижче видалені */
@keyframes orbit {
from { transform: rotate(0deg) translateX(150px); }
to { transform: rotate(360deg) translateX(150px); }
}

Для IE JavaScript доведеться змінити — так як корабель насправді обертається, для відповідальної роботи я використовував тут cssSandpaper.

/*
* Функція заміщення в попередньому прикладі, де
* «Enterprise» завжди звернена в ту сторону, куди рухається.
*/
function rotateOnce() {
$enterprise.css(‘text-indent’, 0);
$enterprise.animate(
{
‘text-indent’: 2*Math.PI
}, {
step: function (now) {
/*
* На відміну від іншого прикладу, нам потрібен об’єкт
* (в даному випадку «Enterprise»), обертається в той час, як
* летить навколо Сонця, тому ми використовуємо cssSandpaper
* для цієї роботи.
*/
cssSandpaper.setTransform($enterprise[0],
‘rotate(‘ + now + ‘rad) translateX(400px)’);
},
duration: 20000,
easing: ‘linear’,
complete: rotateOnce
}
);
}

Погляньте на результат

Псевдо 3D?

Ми також можемо зробити псевдо 3D-анімацію планети, ріже в Сонце. Я надам читачам в якості вправи можливість розглянути CSS і спеціальний JavaScript для IE, щоб обчислити, як це працює (якщо ви розумієте наведені вище приклади, то зможете розібратися).

Подальше вивчення?

Відразу після написання цього тексту я натрапив на чудову статтю в Smashing Magazine – Керівництво по анімації CSS: принципи та приклади (The Guide To CSS Animation: Principles and Example) Тома Уотерхауса (Tom Waterhouse). У ній є чудові приклади, які включають просунуту анімацію CSS3, поєднання анімації двох вкладених об’єктів DOM для твору ефекту скаче м’яча. Я впевнений, що з їх допомогою можна зробити набагато більш цікаві техніки, і виразно продовжу дослідити анімацію CSS3 в майбутньому. Якщо можете поділитися подібними статтями, я (і, впевнений, інші читачі цієї статті) хотіли б про них прочитати.