[Перевод] Знакомимся с Web Animations API

vziyc7iwexatwqry7oyh3apukf8.png

Доброго времени суток, друзья!

Представляю Вашему вниманию перевод статьи 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 на простом примере.
Ниже мы видим вращающийся квадрат, цвет которого меняется с каждым поворотом.

re7dxbnzzzjk9uu_4bktqx7bdzy.gif

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


Данный код заставляет квадрат вращаться быстрее при клике.

bceuwuajytywsieq0ecqduibo6s.gif

До сих пор мы изучали, как создавать одну анимацию и управлять ее воспроизведением. Другой возможностью 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
    }
)


Таким образом, мы используем время анимации первого квадрата для определения времени анимации второго квадрата. Теперь при изменении времени анимации первого квадрата, второй всегда будет вращаться в два раза быстрее!

uhaapf7c9xqtam-g7ilo0hqal7i.gif

Производительность


Говоря о производительности, я не заметила особой разницы между использованием CSS и WAAPI. Но это может быть связано с простотой моего примера.

Одним важным преимуществом WAAPI по сравнению с другими способами создания анимации в JS является то, что он выполняется в отдельном потоке, что позволяет основному потоку «забыть» про анимацию и заниматься остальным кодом.

Поддержка браузеров


В настоящее время WAAPI находится в статусе черновика и частично поддерживается в последних версиях Firefox и Chrome, а также в основных мобильных браузерах.

Частичная поддержка означает, что браузеры поддерживают такие методы как play, pause, reverse, finish и playbackRate, но не поддерживают getAnimations.

ag2ar2ipolk7xfiwxi_mdjbmzao.png

Существует полифил для работы WAAPI во всех браузерах.

На этом у меня все!

Дополнительная литература:

Using the Web Animations API
Web Animations API examples
Great series «Let’s talk about the Web Animations API» by Dan Wilson

Благодарю за внимание.

© Habrahabr.ru