CSS-анімація: властивість transition. Шарувата анімація

20

Від автора: CSS анімація і зокрема властивість transition – відмінний спосіб плавно пересунути об’єкт з точки А у точку В. Все це добре працює, якщо ви рухаєте предмет по прямій. Не важливо, скільки разів ви зігнете криві Безьє, у вас не вийде змусити рухатися об’єкт по кривій лінії за допомогою властивостей animation і transition. Можна помилитися з тимчасової функцією, що призведе до ефекту пружини, руху відносно осей Х і У завжди будуть однаковими.

Тим не менш, є більш легкий спосіб для створення такої натуральної анімації без допомоги JavaScript – шарувата анімація. Використовуючи два або більш об’єкта для анімації, можна контролювати будь-яку ділянку шляху. Одну таймінг функцію можна застосувати до руху по осі Х, іншу – до руху по осі У.

Проблема

Перед тим як ми перейдемо до рішення, давайте ближче розглянемо проблему. CSS властивості animation і transition обмежують нас рухом тільки по прямій. Як це відбувається? Завжди вибирає найкоротший шлях від точки А до точки Ст. Відмінно – в більшості випадків цього достатньо – однак ми не можемо сказати CSS пройтися «красивим шляхом», а не «коротким».

Найпростіший спосіб в CSS-анімації від однієї точки до іншої (з апаратним прискоренням) це властивість transform зі значенням translate. Таким чином можна отримати рух вздовж прямої. В @keyframes блоці нижче ми рухаємося вгору і вниз з точки (0, 0) у точку (100, -100), як у наведеному вище прикладі:

@keyframes straightLine {
50% {
transform: translate3D(100px, -100px, 0);
}
}
.dot {
animation: straightLine 2.5 s infinite linear;
}

Це нескладно, але давайте зупинимося. Щоб зрозуміти, як розв’язати нашу задачу, необхідно хоча б візуально розбити нашу анімацію на частини.

0% об’єкт знаходиться у точці (0, 0), на 50% ми використовуємо translate3D(100px, -100px, 0) для переміщення в точку (100, -100), потім ідемо назад. Перефразовуючи, ми рухаємо об’єкт на 100px вправо і потім на 100px вгору. Два переходи разом рухають об’єкт у верхній кут.

Рішення: одна функція на вісь

Так як же створити рух по кривій, як показано вище? Щоб об’єкт рухався не по прямій лінії необхідно, щоб швидкість пересування по осях Х і У, була різною.

У попередніх прикладах скрізь використовувалася функція linear, однак якщо обернути наш об’єкт в контейнер, то одну функцію можна застосувати для пересування по Х, а іншу для пересування по У. Нижче ми використовуємо ease-in для осі Х і ease out для:

Реалізація: один об’єкт на вісь

На жаль, ми не можемо задати кілька властивостей transform, буде застосовано тільки останнє. Так як же насправді поєднати дві анімації? Ми помістимо один об’єкт всередину іншого і запустимо одну анімацію для контейнера, а іншу для дочірнього елемента.

У всіх наведених вище прикладах з двигающейся точкою вздовж кривої ви бачили, як анімації піддавалися два елемента, а контейнер був повністю прозорий. Щоб зрозуміти, як два об’єкти взаємодіють між собою, і як виходить рух по кривій, ми зробили видимим контейнер за допомогою значення border-box:

Точка розташовується усередині боксу і рухається разом з ним по осі Х, у той час як сама точка переміщується по осі У. Якщо прибрати рамку контейнера, то ми отримаємо пересування кривої. Замість використання двох об’єктів в HTML можна додати псевдоклас. Якщо HTML виглядає так:

Можна додати псевдоклас:

.dot {
/* Контейнер. Переміщається по осі X */
}
.dot::after {
/* Розмальовує точку і переміщує її вздовж осі y */
}

Нам потрібно два окремих блоки анімації: один для осі Х, інший для У. Зверніть увагу, як у першому блоці використовується ease-in, а в другому ease-out:

.dot {
/* тут іде код… */
animation: xAxis 2.5 s infinite ease-in;
}
.dot::after {
/* Точка */
animation: yAxis 2.5 s infinite ease-out;
}
@keyframes xAxis {
50% {
animation-timing-function: ease-in;
transform: translateX(100px);
}
}
@keyframes yAxis {
50% {
animation-timing-function: ease-out;
transform: translateY(-100px);
}
}

Додамо вендорные префікси для WebKit браузерів і парочку кривих Безьє замість ease-in і ease-out, і у нас вийде приклад, показаний на початку статті:

.demo-dot {
-webkit-animation: xAxis 2.5 s infinite cubic-bezier(0.02, 0.01, 0.21, 1);
animation: xAxis 2.5 s infinite cubic-bezier(0.02, 0.01, 0.21, 1);
}
.demo-dot::after {
content: «;
display: block;
width: 20px;
height: 20px;
border-radius: 20px;
background-color: #fff;
-webkit-animation: yAxis 2.5 s infinite cubic-bezier(0.3, 0.27, 0.07, 1.64);
animation: yAxis 2.5 s infinite cubic-bezier(0.3, 0.27, 0.07, 1.64);
}
@-webkit-keyframes yAxis {
50% {
-webkit-animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1);
animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1);
-webkit-transform: translateY(-100px);
transform: translateY(-100px);
}
}
@keyframes yAxis {
50% {
-webkit-animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1);
animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1);
-webkit-transform: translateY(-100px);
transform: translateY(-100px);
}
}
@-webkit-keyframes xAxis {
50% {
-webkit-animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64);
animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64);
-webkit-transform: translateX(100px);
transform: translateX(100px);
}
}
@keyframes xAxis {
50% {
-webkit-animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64);
animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64);
-webkit-transform: translateX(100px);
transform: translateX(100px);
}
}

Код приведе нас до того, з чого ми почали.

Ви, мабуть, вже помітили, що в усіх прикладах ми використовували @keyframes анімацію. Однак це тільки тому, що нам треба було рухати точку назад і вперед. Якщо необхідно пересунути об’єкт з точки А в точку в, шарувата анімація добре працює з властивістю transition.

Якщо об’єкт пропонується абсолютно, анімувати по кривій лінії його можна за допомогою властивостей left bottom. В такому випадку вам знадобиться тільки один об’єкт, контейнер додавати не треба. Тим не менш, є причина, по якій слід уникати такої анімації: продуктивність такої анімації дуже низька, і вона малюється на кожному кадрі заново. Шарувата ж анімація з псевдоклассами і апаратним прискоренням властивості translate робить пересування дуже плавним, не знижуючи продуктивність.