Веб-анимация — element.animate() теперь в Chrome 36.

Брендан Кенни
Brendan Kenny

Анимация в Интернете когда-то была прерогативой JavaScript, но по мере того, как мир перешел на мобильные устройства, анимация перешла на CSS для декларативного синтаксиса и оптимизации, которую браузеры могли с его помощью выполнять. Поскольку ваша цель — 60 кадров в секунду на мобильных устройствах, имеет смысл никогда не выходить за рамки того, что браузеры умеют эффективно отображать.

Появляется больше инструментов, позволяющих сделать анимацию на основе JavaScript более эффективной, но святым Граалем является объединение декларативной и императивной анимации , где решение о том, как писать анимации, основано на том, какой самый ясный код, а не на том, что возможно в одной форме. и не в другом.

Веб-анимация призвана ответить на этот вызов, и первая ее часть появилась в Chrome 36 в виде element.animate() . Эта новая функция позволяет создавать анимацию исключительно на JavaScript и запускать ее так же эффективно, как и любую CSS-анимацию или переход (фактически, начиная с Chrome 34, всеми этими методами управляет один и тот же движок веб-анимации ).

Синтаксис прост, и его части должны быть вам знакомы, если вы когда-либо писали CSS-переход или анимацию:

element.animate([
    {cssProperty: value0},
    {cssProperty: value1},
    {cssProperty: value2},
    //...
], {
    duration: timeInMs,
    iterations: iterationCount,
    delay: delayValue
});

Самым большим преимуществом этой новой функции является устранение множества неудобных препятствий, через которые нам раньше приходилось преодолевать, чтобы получить плавную анимацию без рывков.

Например, в прошлом году для Santa Tracker мы хотели, чтобы снег падал непрерывно, и решили анимировать его с помощью CSS, чтобы это можно было сделать настолько эффективно .

Однако мы хотели динамически выбирать горизонтальное положение снега на основе экрана и событий, происходящих в самой сцене, и, конечно же, высота падения снега (высота окна браузера пользователя) не будет известна до тех пор, пока мы на самом деле не бег. Это означало, что нам действительно пришлось использовать CSS-переходы, поскольку создание CSS-анимации во время выполнения быстро усложняется (а сотни снежинок означают сотни новых правил стилизации).

Поэтому мы выбрали следующий подход, который должен быть вам знаком:

snowFlake.style.transform = 'translate(' + snowLeft + 'px, -100%)';
// wait a frame
snowFlake.offsetWidth;
snowFlake.style.transitionProperty = 'transform';
snowFlake.style.transitionDuration = '1500ms';
snowFlake.style.transform = 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)';

Ключ в этом комментарии «подожди кадра». Чтобы успешно начать переход, браузер должен подтвердить, что элемент находится в начальной позиции. Есть несколько способов сделать это. Один из наиболее распространенных способов — чтение одного из свойств элемента, которое заставляет браузер вычислять макет, тем самым гарантируя, что он знает, что элемент имеет начальную позицию, прежде чем перейти к конечной позиции. Использование этого метода позволяет вам поздравить себя с превосходным знанием внутреннего устройства браузера, но при этом чувствовать себя грязным при каждом нажатии клавиши.

Напротив, эквивалентный вызов element.animate() не может быть более ясным, точно говоря, что именно предназначено:

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);

Есть еще много вариантов. Как и в случае с аналогами CSS, веб-анимацию можно откладывать и повторять:

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], {
    duration: 1500,
    iterations: 10,
    delay: 300
});

Анимационный плеер

element.animate() фактически возвращает объект AnimationPlayer, который будет становиться все более важным по мере запуска новых спецификаций веб-анимации. Анимации, созданные как на JavaScript, так и на CSS, будут иметь связанные AnimationPlayers, что позволит их легко комбинировать полезными и интересными способами.

Однако на данный момент AnimationPlayer имеет только две функциональные возможности, обе очень полезные. Вы можете отменить анимацию в любое время, используя AnimationPlayer.cancel() :

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
// less than 1500ms later...changed my mind
player.cancel();

И, к облегчению всех, кто в прошлом пытался построить систему анимации на основе CSS-анимаций или переходов, веб-анимация всегда запускает событие по завершении:

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
player.onfinish = function(e) {
    console.log('per aspera ad terra!');
}

Попробуйте это

Все это доступно в Chrome 36, который сегодня перейдет в бета-версию! Если вы хотите попробовать это, попробуйте поработать с собственной реализацией в Chrome 36. Однако существует полифилл Web Animations , который привносит значительно большую часть полной спецификации Web Animations в любой из современных, постоянно обновляющихся браузеров.

Вы можете попробовать демо-версию эффекта снега, используя как собственную версию element.animate() , так и полифил .

Поделитесь с нами вашими мыслями

На самом деле, это лишь предварительный просмотр того, что будет дальше, и он выпущен специально для того, чтобы сразу же получить отзывы разработчиков. Мы еще не уверены, что мы учли все варианты использования или отшлифовали все неровности текущих API для анимации. Единственный способ узнать и по-настоящему понять это правильно — это чтобы разработчики опробовали это и сообщили нам, что они думают.

Комментарии к этому посту, конечно, ценны, а комментарии к самому стандарту можно адресовать рабочим группам CSS и SVG через список рассылки public-fx .

Обновление, октябрь 2014 г .: в Chrome 39 добавлена ​​поддержка нескольких дополнительных методов , связанных с управлением воспроизведением, таких как play() , pause() и reverse() . Он также поддерживает переход к определенной точке временной шкалы анимации через свойство currentTime . Вы можете увидеть эту функциональность в действии в этой новой демонстрации .

Спасибо Адди Османи и Максу Хайнритцу за помощь в написании этого поста.