MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

Перевод не завершен. Пожалуйста, помогите перевести эту статью с английского.

Веб - API Animations позволяет нам создать анимацию и управлять её воспроизведением с помощью JavaScript. Эта статья будет правильным руководством для старта c веселыми демками и уроками с Алисой в Стране Чудес.

Встречайте Web Animations API

В Web Animations API открывает анимацию на движке браузеров для разработчиков и манипуляции через (с помощью) JavaScript.
Этот API был разработан в основе реализации CSS Animations и CSS Transitions, и оставлял свободу движений для будущих анимационных эффектов. Это один из самых эффективных способов анимации, поддерживаемой в Интернете, позволяя браузеру сделать свою собственную внутреннюю оптимизацию без хаков, принуждения, или Window.requestAnimationFrame().

С Web Animations API, мы можем управлять интерактивной анимацией с стилями  JavaScript, отделяя представление от действия. Нам больше не нужно полагаться  на DOM-heavy методики написания CSS свойств и обзорных классов для элементов контроля воспроизведения направления. И в отличии от чисто декларативного CSS, JavaScript также позволяет устанавливать динамические значения свойств и их продолжительность. Для создания пользовательских библиотек и интерактивной анимации Web Animations API может стать прекрасным инструментом в работе. Давайте посмотрим, что он может сделать!

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

Основы и компоненты Web Animations API, описанные в этой статье доступны в Firefox 48+ и Chrome 36+. Webkit и Edge перешли на  API соответственно, но пока нет полной поддержки во всех браузерах, есть удобная служба проверки handy maintained polyfill которая тестирует и добавляет ее при необходимости.

Написание CSS Animations вместе с Web Animations API

Самый простой способ в обучении Web Animations API это начать с чего начинало большинство веб-разработчиков: CSS Animations. В CSS Animations есть знакомый синтаксис, который хорошо раскрывает структуры демонстрационных примеров.

CSS версия

Вот такая анимация написана в CSS, показывающая, как Алиса падает в кроличью нору, которая ведет в страну чудес (см. полный код на Codepen):

Alice Tumbling down the rabbit's hole.

Заметьте, что фон двигается, Алиса крутится и ее цвет меняется при вращении. Мы собираемся сосредоточиться только на Алисе в этом уроке. Вот упрощенный код CSS, который управляет движением Алисы.

#alice {
  animation: aliceTumbling infinite 3s linear;
}

@keyframes aliceTumbling {
  0% {
    color: #000;
    transform: rotate(0) translate3D(-50%, -50%, 0);    
  }
  30% {
    color: #431236;
  }
  100% {
    color: #000;
    transform: rotate(360deg) translate3D(-50%, -50%, 0);
  }
}

Изменение цвета Алисы и ее вращение в течение 3 секунд при постоянной (линейной) скорости и бесконечном цикле. В @keyframes блоке мы видим, что 30%  из всего цикла (около 9 секунд), цвет Алисы меняется от черного до насыщенного бордового, а потом снова в черный к концу цикла.

Движение в JavaScript

Теперь давайте попробуем создать такую же анимацию с Web Animations API.

Представляя кадры

В первую очередь мы должны сосздать Keyframe Object соответствующего нашему CSS @keyframes блоку:

var aliceTumbling = [
  { transform: 'rotate(0) translate3D(-50%, -50%, 0)', color: '#000' },
  { color: '#431236', offset: 0.333},
  { transform: 'rotate(360deg) translate3D(-50%, -50%, 0)', color: '#000' }
];

Здесь мы используем массив, содержащий несколько объектов. Каждый объект представляет собой код от оригинального CSS. Однако, в отличие от CSS, Web Animations API не нужно назначать точные проценты по анимации для каждого открывающего кода. Он автоматически разделит анимацию на равные части в соответствии с количеством кодов, которые вы ему даете. Это означает, что объект Keyframe с тремя кодами будет воспроизводить средний код 50% времени через каждый цикл анимации если не указано иное.

Если мы хотим, чтобы определенный набор кода смещался относительного другого кода, мы можем указать смещение непосредственно на объекте который будет меняться, отделив значение запятой. В приведенном выше примере видно, чтобы цвет Алисы менялся на 30%, а не на 50% всего цикла, мы задаем смещение: 0,333.

Там должно быть как минимум два кадра (представляющих начало и конец анимации). Если в вашем списке keyframe только одна запись, Element.animate() то анимация выполняться не будет, вы получите ошибку NotSupportedError exception.

И так повторим, код равномерно распределен по умолчанию, если не указано смещение. Удобно, не так ли?

Представление свойства времени.

Мы также должны создать объекту временные свойства (an AnimationEffectTimingProperties object) соответствующие значению анимации Алисы:

var aliceTiming = {
  duration: 3000,
  iterations: Infinity
}

Вы увидите здесь несколько отличий того, как соответствующие значения представлены в CSS:

  • Во-первых, длительность в миллисекундах, в отличии от секунд - 3000, а не 3с. Как WindowTimers.setTimeout() и Window.requestAnimationFrame(), Web Animations API использует только миллисекунды.
  • Во-вторых, что вы заметили, что он итерационный (повторяется), а не счетчик повторений.

Существует ряд небольших различий между терминологией, используемой в анимации CSS и терминологии, которая используется в веб-анимации. Например, веб-анимации не используется строка "бесконечное", а вместо этого использует JavaScript код бесконечность. И вместо временной-функции мы используем ослабление. Мы не будем перечислять здесь значение ослабления, потому что, в отличие от CSS анимации, где по умолчанию animation-timing-function это просто, в веб-анимации API для ослаблеия по умолчанию используется линейная зависимость - котрые мы используем здесь

Собираем части вместе.

Сейчас соберем все части вместе используя Element.animate() метод:

document.getElementById("alice").animate(
  aliceTumbling,
  aliceTiming
)

И вуаля, анимация работает(смотрите готовый вариант на version on Codepen).

The animate() метод может быть применен на любой DOM-элемент, который может быть анимирован с помощью CSS. И он может быть записан несколькими способами. Вместо того, чтобы делить объекты на ключевые кадры и временные характеристики, мы могли бы просто передать свои значения непосредственно вот так:

document.getElementById("alice").animate(
  [
    { transform: 'rotate(0) translate3D(-50%, -50%, 0)', color: '#000' },
    { color: '#431236', offset: 0.333},
    { transform: 'rotate(360deg) translate3D(-50%, -50%, 0)', color: '#000' }
  ], {
    duration: 3000,
    iterations: Infinity
  }
);

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

document.getElementById("alice").animate(
  [
    { transform: 'rotate(0) translate3D(-50%, -50%, 0)', color: '#000' },
    { color: '#431236', offset: 0.333},
    { transform: 'rotate(360deg) translate3D(-50%, -50%, 0)', color: '#000' }
  ], 3000);

Управление воспроизведением с помощью play(), pause(), reverse() and playbackRate

Хотя мы можем писать CSS анимацию с Web Animations API, где API действительно хорошо подходит в качестве воздействия для воспроизведения анимации. Web Animations API обеспечивает несколько удобных методов для контроля воспроизведения анимации. Давайте посмотрим на паузу и воспроизведение анимации в росте/уменьшении Алисы в игре (провериить полный код можно на сайте full code on Codepen):

Playing the growing and shrinking game with Alice.

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

Пауза и проигрывание анимации.

Мы поговорим об анимации Алисы позже, а сейчас посмотрим поближе на анимации кекса:

var nommingCake = document.getElementById('eat-me_sprite').animate(
[
  { transform: 'translateY(0)' },
  { transform: 'translateY(-80%)' }   
], {
  fill: 'forwards',
  easing: 'steps(4, end)',
  duration: aliceChange.effect.timing.duration / 2
});

Метод Element.animate() будет выполняться сразу же как начнется игра. Чтобы предотвратить автоматическое поедание кекса до того, как пользователь на него нажмет, мы вызываем Animation.pause() сразу же как игра открывается, например так:

nommingCake.pause();

Теперь мы можем запустить метод Animation.play() когда будем готовы:

nommingCake.play();

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

var growAlice = function() {

  // Play Alice's animation.
  aliceChange.play();

  // Play the cake's animation.
  nommingCake.play();

}

Когда пользователь поместит указатель мыши вниз или нажимает пальцем на торт на сенсорном экране, мы можем вызвать growAlice, чтобы выполнить все анимации:

cake.addEventListener("mousedown", growAlice, false);
cake.addEventListener("touchstart", growAlice, false);

Другие полезные методы.

Помимо паузы и воспроизведения, мы можем использовать следующие методы анимации:

  • Animation.finish() перейти в конец анимации.
  • Animation.cancel() прервать анимацию и удалить ее эффект.
  • Animation.reverse() устанавливать скорость анимации если установить (Animation.playbackRate отрицательное значение, то анимация пойдет в обратном порядке.

Давайте посмотрим на первый playbackRate— отрицательное значение будет запускать анимацию в обратном направлении. Когда Алиса пьет из бутылки, она становится меньше. Это происходит потому, что бутылка изменяет ее анимацию playbackRate от 1 до -1:

var shrinkAlice = function() {
  aliceChange.playbackRate = -1;
  aliceChange.play();
}

bottle.addEventListener("mousedown", shrinkAlice, false);
bottle.addEventListener("touchstart", shrinkAlice, false);

В Through the Looking-Glass, Алиса путешествует по миру, где должна бежать, чтобы оставаться на месте и бежать в двое быстрее, чтобы двигаться вперед. Например в гонке с Красной королевой, Алиса и Красная королева бегут, чтобы оставаться на месте (проверить полный код можно на full code on Codepen):

Alice and the Red Queen race to get to the next square in this game.

Так как маленькие дети легко устают, в отличии от шахматных фигур, Алиса постоянно замедляется. Мы отобразили это в коде путем ослабления (уменьшения скорости) playbackRate анимации.

setInterval( function() {

  // Make sure the playback rate never falls below .4
  if (redQueen_alice.playbackRate > .4) {
    redQueen_alice.playbackRate *= .9;    
  }

}, 3000);

Но постоянно нажимая на них мышью, мы заставляем их ускориться путем умножения playbackRate (скорости анимации)

var goFaster = function() {

  redQueen_alice.playbackRate *= 1.1;

}

document.addEventListener("click", goFaster);
document.addEventListener("touchstart", goFaster);

Фон также ускоряется при щелчках мыши или касаниях. Что же происходит, когда вы заставляете Алису и Красную королеву бежать в два раза быстрее? Что происходит, когда они тормозят?

Получение информации из анимации

Представьте, что мы могли бы использовать playbackRate, как улучшения доступности сайта для пользователей с вестибулярными расстройствами, позволяя им замедлить анимацию на всех страницах сайта. Это невозможно сделать с помощью CSS без пересчета длительности в каждом правиле CSS, но с веб-анимации API, мы могли бы использовать в будущем (пока не поддерживается в браузерах!) Метод document.getAnimations() систему циклов по каждой анимации на странице и сократить скорость анимации вот так:

document.getAnimations().forEach(
  function (animation) {
    animation.playbackRate *= .5;
  }
);

С Web Animations API нужно изменить только одно свойство.

Другое дело, что это трудно делать только с CSS Animations, создавать зависимости от значения предусмотренные для других анимации. В примере игры про рост и уменьшение Алисы, вы можете заметить некоторые странности у кекса:

duration: aliceChange.effect.timing.duration / 2

Чтобы понять, что здесь происходит, давайте посмотрим на анимацию Алисы:

var aliceChange = document.getElementById('alice').animate(
  [
    { transform: 'translate(-50%, -50%) scale(.5)' },
    { transform: 'translate(-50%, -50%) scale(2)' }   
  ], {
    duration: 8000,
    easing: 'ease-in-out',
    fill: 'both'
  });

Изменение размера Алисы в два раза происходит за 8 секунд. Затем мы останавливаем ее:

aliceChange.pause();

Если бы оставили ее на паузе в начале анимации , то Алиса увеличилась бы в два раза, когда выпила бы всю бутылку. Мы хотим остановить ее анимацию "воспроизведение" в середине, когда она уже на половину выполнена. Мы могли бы это сделать, установив Animation.currentTime 4 секунды, вот так:

aliceChange.currentTime = 4000;

Но во время работы над этой анимацией мы можем сильно увеличить ее продолжительность. Разве не лучше установить динамическое изменение времени (currentTime), тогда нам не придется делать два обновления за один раз. Мы можем это сделать с помощью ссылки на изменение свойства размера Алисы (aliceChange) Animation.effect который возвращает все детали и действующие эффекты, содержащиеся в объекте, на Алису:

aliceChange.currentTime = aliceChange.effect.timing.duration / 2;

эффекты позволяют нам получить доступ к анимации keyframe (кадров) и синхронности объектов - aliceChange.effect.timing , указывающий на время Алисиных элементов (котрые имеют тип AnimationEffectTimingReadOnly) — в этом содержиться ее AnimationEffectTimingReadOnly.duration. Мы можем распределить ее длительность на два раза, чтобы получить среднюю точку во временной шкале для установки нормального роста.

Теперь мы можем запустить ее в обратном порядке и играться анимацией в любом направлении, чтобы заставить ее расти или уменьшаться

var drinking = document.getElementById('liquid').animate(
[
  { height: '100%' },
  { height: '0' }   
], {
  fill: 'forwards',
  duration: aliceChange.effect.timing.duration / 2
});
drinking.pause();

И мы можем сделать тоже самое при установки длительности анимации на кексе или бутылке.

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

Мы также можем использовать веб-анимации API, чтобы выяснить Текущее время анимации. Игра заканчивается, когда вы бежите от съеденого торта или выпитой бутылки. Изображение у игрока будет зависить от анимации Алисы. Стала ли она слишком большой на фоне крошечной двери и не может в нее пройти или слишком маленькой и не может достать ключ, чтобы открыть дверь. Мы можем выяснить, стала она большой или маленький в конце ее анимация, получая текущее время ее анимации currentTime и разделив ее на activeDuration:

var endGame = function() {
  
  // get Alice's timeline's playhead location
  var alicePlayhead = aliceChange.currentTime;
  var aliceTimeline = aliceChange.effect.activeDuration;

  // stops Alice's and other animations
  stopPlayingAlice();

  // depending on which third it falls into
  var aliceHeight = alicePlayhead/aliceTimeline;

  if (aliceHeight <= .333){
    // Alice got smaller!
    ...

  } else if (aliceHeight >= .666) {
    // Alice got bigger!
    ...

  } else {
    // Alice didn't change significantly    
    ...

  }
}

Примечание: getAnimations() и эффект не полностью поддерживаются на момент написания этой статьи, но polyfill  поддерживает их уже сегодня.

Обратные вызовы и обещания

CSS Animations и Transitions (переходы) имеют свои события и они также могут быть воспроизведены и в Web Animations API:

  • onfinish это обработчик событий для завершения события и он может быть запущена вручную в функйи/команды finish().
  • oncancel это обработчик для отмены события и может быть запуен с помощью функции/команды cancel().

Здесь мы устанавливаем обратный вызов для бутылки, кекса и Алисы, чтобы запустить функцию endGame.

// When the cake or runs out... 
nommingCake.onfinish = endGame;
drinking.onfinish = endGame;

// ...or Alice reaches the end of her animation
aliceChange.onfinish = endGame;

Нравится перспектива? Web Animations API также дает две перспективы: onfinish и oncancel.

Эти обещания не полностью поддерживаются в настоящий момент.

Заключение

Таковы основные особенности веб-анимации API, большинство из которых уже поддерживается в последних версиях Firefox и Chrome. К этому моменту вы должны быть готовы к "прыжку в кроличью нору" анимации в браузере и готовы написать свои собственные эксперименты в анимации! Если вы используете API и хотите поделиться, попробуйте использовать хэштег #WAAPI. Мы будем следить и писать другие учебники, чтобы охватить будущие дополнительные функции, в виде поддержки распространяя!

Посмотрите также

Метки документа и участники

Метки: 
 Внесли вклад в эту страницу: pavelmarozka
 Обновлялась последний раз: pavelmarozka,