Доброго времени суток, друзья!
Представляю Вашему вниманию перевод статьи Charlie Gerard «Exploring the Web Animations API».
Знакомимся с Web Animations API
Веб API постоянно эволюционируют. Некоторые из них, такие как Console или Canvas, хорошо поддерживаются всеми браузерами, другие по-прежнему находятся на стадии разработки.
Одним из API, находящимся на стадии разработки, является Web Animations API или WAAPI. Несмотря на то, что первый вариант спецификации был опубликован в 2012 году, а сам API впервые реализован в браузерах Firefox и Chrome в 2014 году, я узнала о нем совсем недавно (я тоже раньше о нем не слышал — прим.пер.).
Он позволяет разработчикам работать с CSS анимацией средствами JavaScript. Его синтаксис похож на синтаксис традиционной CSS анимации, но имеет некоторые особенности, которые облегчают разработчикам создание и изменение анимации.
Давайте рассмотрим этот API на простом примере.
Ниже мы видим вращающийся квадрат, цвет которого меняется с каждым поворотом.
CSS-код может выглядеть так:
#cube {
width: 40px;
height: 40px;
margin: 50%;
background-color: pink;
animation: rotateCube 1s infinite;
}
@keyframes rotateCube {
0% {
transform: rotate(0deg);
}
30% {
background-color: purple;
}
100% {
transform: rotate(180deg);
}
}
Теперь сделаем тоже самое с помощью WAAPI.
Создание анимации
Все начинается с создания объекта Keyframes, содержащего информацию, аналогичную той, которая содержится в директиве @keyframes нашего CSS:
let cubeRotating = [
{transform: 'rotate(0deg)', backgroundColor: 'pink'},
{backgroundColor: 'purple', offset: 0.3},
{transform: 'rotate(180deg)', backgroundColor: 'pink'}
]
Мы видим два главных отличия:
- Нам необходимо добавить backgroundColor в другие шаги.
- Нам не нужно определять время выполнения каждого шага в процентах.
WAAPI автоматически делит анимацию на равные части по количеству ключей, поэтому в нашем случае цвет фона будет меняться примерно на половине анимации.
Однако мы хотим, чтобы это происходило на 30%, поэтому мы добавляем во второй шаг свойство offset со значением 0.3.
Необходимо запомнить одну важную вещь: в объекте Keyframes должно быть как минимум два ключа. В противном случае, будет выброшена ошибка NotSupportedError.
Далее создается объект, содержащий свойства анимации, отвечающие за продолжительность и количество повторов:
let cubeTiming = {
duration: 1000,
iterations: Infinity
}
Продолжительность анимации устанавливается в миллисекундах.
Вместо «infinite» мы используем ключевое слово «Infinity».
Наконец, для запуска анимации мы используем метод Element.animate:
document.getElementById('cube').animate(
cubeRotating,
cubeTiming
)
Существует еще несколько вариантов синтаксиса. Примеры можно посмотреть здесь.
Но это еще не все. Дело в том, что с помощью WAAPI мы может управлять воспроизведением анимации!
Управление воспроизведением анимации
Вызов метода animate запускает анимацию немедленно, но это не всегда то, чего мы хотим. Поэтому мы можем вызывать методы pause и play для остановки и запуска анимации, соответственно:
let cubeAnimation = document.getElementById('cube').animate(
cubeRotating,
cubeTiming
)
cubeAnimation.pause()
document.body.onclick = () => cubeAnimation.play()
В нашем примере мы работаем с одной анимацией, но вы вполне можете добавить на страницу несколько «анимаций» и управлять ими, как заблагорассудится.
Среди доступных методов WAAPI также есть методы finish, cancel и reverse.
Также мы можем управлять скоростью воспроизведения анимации:
let cubeAnimation = document.getElementById('cube').animate(
cubeRotating,
cubeTiming
)
document.body.onclick = () => cubeAnimation.playbackRate *= 1.5
Данный код заставляет квадрат вращаться быстрее при клике.
До сих пор мы изучали, как создавать одну анимацию и управлять ее воспроизведением. Другой возможностью WAAPI является доступ ко всем анимациям сразу.
Управление множеством анимаций
У WAAPI есть метод getAnimations, позволяющий получить доступ ко всем созданным анимациям.
Допустим, мы хотим замедлить все анимации, имеющиеся на странице, если пользователь включил prefers-reduced-motion (CSS медиа функция prefers-reduced-motion может использоваться для определения того, запросил ли пользователь, чтобы ОС минимизировала количество анимации или движения, которые она использует — прим. пер.):
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)')
if(mediaQuery.matches){
document.getAnimations().forEach(animation => {
animation.playbackRate *= 0.5
})
}
В примере выше мы ищем медиа функцию prefers-reduced-motion и, если ее значение равняется reduce, получаем все анимации на странице и уменьшаем скорость их воспроизведения наполовину.
Эта одна из тех вещей, которые делают WAAPI очень полезной. Мы можем вносить изменения в несколько анимаций посредством изменения одного свойства.
Зависимости
Еще одной интересной возможностью WAAPI является возможность определить зависимость свойств одной анимации от свойств другой.
Например, если у нас есть два квадрата, и мы хотим, чтобы второй вращался в два раза быстрее первого, мы можем сделать это двумя способами.
Первый способ:
let cube1Animation = document.getElementById('cube').animate(
cubeRotating,
{
duration: 1000,
iterations: Infinity
}
)
let cube2Animation = document.getElementById('cube2').animate(
cubeRotating,
{
duration: 500,
iterations: Infinity
}
)
Время анимации первого квадрата составляет 1 секунду, второго — 500 миллисекунд.
Однако при таком подходе, когда мы меняем время анимации первого квадрата, нам нужно сделать тоже самое у второго квадрата.
Представляете, насколько это станет сложным при наличии множества анимаций или большого количества анимированных объектов?
Лучшим способом решить нашу задачу является установление зависимости вращения второго квадрата от первого:
let cube1Animation = document.getElementById('cube').animate(
cubeRotating,
{
duration: 1000,
iterations: Infinity
}
)
let cube2Animation = document.getElementById('cube2').animate(
cubeRotating,
{
duration: cube1Animation.effect.timing.duration / 2,
iterations: Infinity
}
)
Таким образом, мы используем время анимации первого квадрата для определения времени анимации второго квадрата. Теперь при изменении времени анимации первого квадрата, второй всегда будет вращаться в два раза быстрее!
Производительность
Говоря о производительности, я не заметила особой разницы между использованием CSS и WAAPI. Но это может быть связано с простотой моего примера.
Одним важным преимуществом WAAPI по сравнению с другими способами создания анимации в JS является то, что он выполняется в отдельном потоке, что позволяет основному потоку «забыть» про анимацию и заниматься остальным кодом.
Поддержка браузеров
В настоящее время WAAPI находится в статусе черновика и частично поддерживается в последних версиях Firefox и Chrome, а также в основных мобильных браузерах.
Частичная поддержка означает, что браузеры поддерживают такие методы как play, pause, reverse, finish и playbackRate, но не поддерживают getAnimations.
Существует полифил для работы WAAPI во всех браузерах.
На этом у меня все!
Дополнительная литература:
Using the Web Animations API
Web Animations API examples
Great series «Let's talk about the Web Animations API» by Dan Wilson
Благодарю за внимание.
Автор: aio350