От автора: Долгое время я предполагал, что нельзя применять CSS Transitions или анимацию для передвижения объектов DOM каким-либо другим образом, кроме движения по прямой. Конечно, разработчик мог бы применить множество ключевых кадров для создания списка прямых путей и симулировать кривую, но не думал, что можно определить кривую с помощью всего двух ключевых кадров или простого CSS transition. Я ошибался.
Вышеприведенный пример анимирован с помощью всего двух ключевых кадров анимации CSS3! Хотя вы могли применить для этого jQuery.animate() или requestAnimationFrame, лучше взять CSS3 вместо JavaScript’а — полученная анимация всегда гарантированно будет глаже (особенно на мобильных устройствах) плюс может сэкономить энергию батареи. В данной статье приведен рецепт CSS выполнения этого трюка во всех браузерах с включенной анимацией CSS3 с тщательным описанием примененной математики, а также альтернативный вариант для старых версий IE, не поддерживающих анимацию CSS3.
Дайте мне CSS!
Единственная причина, почему CSS здесь такой длинный – повторение кода префикса для браузеров:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
.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’ом) находится в центре, так что передвинем Сатурн так, чтобы тот был прямо на нем:
1 2 3 4 5 |
.saturn { left: 315px; position: absolute; top: 143px; } |
Шаг 2: Используйте translateX() для определения радиуса окружности
Далее нам нужно передвинуть объект на край окружности. Для этого примера диаметр окружности составляет, скажем, 300px. Мы устанавливаем свойство CSS3 transform на transformX(150px) (где 150px – половина от 300px).
1 2 3 4 5 6 7 8 |
.saturn { left: 315px; position: absolute; top: 143px; /* Примечание: Ради краткости я опустил код префикса */ transform: translateX(150px); } |
Шаг 3: Вставьте в сюда один или два rotate().
Если в свойство transform вставить rotate() перед translateX(), то можно использовать его для управления путем по окружности. Чтобы продемонстрировать это, давайте вставим один из 45deg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
.saturn { left: 315px; position: absolute; top: 143px; /* Примечание: Ради краткости я опустил код префикса */ transform: rotate(45deg) translateX(150px); } <pre class="lang:CSS"> <p>Проблема заключается в том, что на вышеприведенной анимации Сатурн не должен вращаться по собственной оси. Поэтому нам нужно добавить rotate(-45deg) после translateX() для вращения Сатурна обратно в его «вертикальном» положении:</p> <img src="//webformyself.com/wp-content/uploads/2013/43/5.jpg" alt="" title="" width="544" height="362" class="aligncenter size-full wp-image-376" /> <pre class="lang:CSS"> .saturn { left: 315px; position: absolute; top: 143px; /* Примечание: Ради краткости я опустил код вендорного префикса */ transform: rotate(45deg) translateX(150px) rotate(-45deg); } |
Шаг 4: Примените код анимации
Теперь для завершения работы давайте применим стили анимации. Нам нужно, чтобы Сатурн вращался вокруг Солнца за 2 seconds, поэтому добавляем подходящий CSS для определения скорости, длины и ослабления нашей анимации:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#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 градусов):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@-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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<!DOCTYPE html> <html lang="en"> <head> <title>Example of Using CSS3 Animations and Circular Paths.</title> <meta charset="utf-8" /> <!—Всегда форсируйте последние средства визуализации IE (даже в intranet) & Chrome Frame Удалите это, если применяете .htaccess --> <link rel="stylesheet" href="//www.useragentman.com/shared/css/useragentmanExample.css" /> <link rel="stylesheet" href="css/transition-circle-keyframes.css" /> <!-- IE не выполняет CSS3 Animations, так что давайте вставим сюда немного кода JS. --> <!--[if lte IE 9 ]> <script type="text/javascript" src="/shared/js/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="js/transition-circle-ie.js"></script> <![endif]--> </head> </html> |
(Обратите внимание на условные комментарии для IE9 и ниже!) transition-circle-ie.js содержит код, который делает анимацию с помощью jquery.animate():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
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 есть статья, которая вам поможет.
Вариации этой техники
А если бы вместо планеты, скажем, вам нужен был космический корабль, вращающийся вокруг Солнца. Вот «классический» пример:
Обратите внимание, что корабль всегда смотрит в ту сторону, в которую летит. Это можно сделать с тем же CSS, что и выше, за исключением того, что вы удалили бы вторую rotate() в свойстве transform:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * Код префикса удален для краткости. */ #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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/* * Функция замещения в предыдущем примере, где * «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 в будущем. Если можете поделиться подобными статьями, я (и, уверен, другие читатели этой статьи) хотели бы о них прочесть.
Автор: Dammit Jim
Источник: //www.useragentman.com/
Редакция: Команда webformyself.
Комментарии (2)