CSS Animations tips and tricks
==============================

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

Запустить анимацию снова
------------------------

Спецификация CSS Animations не предлагает способа запустить анимацию снова. Нет никакого волшебного метода resetAnimation () для элементов, и вы даже не можете просто установить элемент `animation-play-state` в" running " снова. Вместо этого вы должны использовать хитрые трюки, чтобы запустить остановленную анимацию для воспроизведения.

Предлагаем вам один из способов, который мы считаем достаточно надёжным и стабильным.

### HTML содержимое

Во-первых, давайте определим HTML для `<div>` который мы хотим анимировать, и кнопку, которая будет запускать (или воспроизводить) анимацию.


```html
<div class="box"></div>

<div class="runButton">Click me to run the animation</div>
```

### CSS содержимое

Теперь мы определим саму анимацию с помощью CSS. Некоторые стили CSS, которые не важны (стиль самой кнопки "выполнить"), здесь не показаны, для краткости.
```

.runButton {
  cursor: pointer;
  width: 300px;
  border: 1px solid black;
  font-size: 16px;
  text-align: center;
  margin-top: 12px;
  padding-top: 2px;
  padding-bottom: 4px;
  color: white;
  background-color: darkgreen;
  font:
    14px "Open Sans",
    "Arial",
    sans-serif;
}
```



```css
@keyframes colorchange {
  0% {
    background: yellow;
  }
  100% {
    background: blue;
  }
}

.box {
  width: 100px;
  height: 100px;
  border: 1px solid black;
}

.changing {
  animation: colorchange 2s;
}
```


Здесь есть два класса. В классе `"box"` прописано основное описание внешнего вида элемента, без какой-либо анимационной информации. Детали анимации включены в класс `"changing"` , который сообщает, что `@keyframes` (en-US) с именем `"colorchange"` должен использоваться в течение 2 секунд.

Обратите внимание, что каких-либо анимационных эффектов у элемента не наблюдается, т.е. анимации нет.

### JavaScript содержимое

Далее мы рассмотрим JavaScript, который дополняет эту работу. Основа этой техники находится в функции play (), которая вызывается, когда пользователь нажимает на кнопку "Выполнить".


```js
function play() {
  document.querySelector(".box").className = "box";
  window.requestAnimationFrame(function (time) {
    window.requestAnimationFrame(function (time) {
      document.querySelector(".box").className = "box changing";
    });
  });
}
```


Это выглядит странно, не так ли? Это потому, что единственный способ воспроизвести анимацию снова-удалить анимационный эффект, позволить документу пересчитать стили так, чтобы он знал, что вы это сделали, а затем добавить анимационный эффект обратно в элемент. Чтобы это произошло, мы должны быть креативными.

Вот что происходит, когда вызывается функция `play()` :

1. Список классов CSS в элементе сбрасывается до простого "box". Это приводит к удалению всех других классов, которые в настоящее время применяются к элементу, включая класс `"changing"` , который обрабатывает анимацию. Другими словами, мы удаляем анимационный эффект из элемента. Однако изменения в списке классов не вступают в силу до тех пор, пока не будет завершён перерасчёт стиля и не произойдёт обновление, отражающее это изменение.
2. Чтобы убедиться, что стили пересчитаны, мы используем `window.requestAnimationFrame()` с колбэком. Наш колбэк выполняется непосредственно перед следующей перерисовкой документа. Проблема заключается в том,что, поскольку это происходит до перерисовки, перерасчёт стиля ещё не произошёл!
3. Наш колбэк ловко вызывает `requestAnimationFrame()` второй раз! На этот раз колбэк выполняется до следующей перерисовки, то есть после того, как произошла перерасчёт стиля. Этот колбэк добавляет класс `"changing"` обратно в элемент, так что перерисовка снова запустит анимацию.

Конечно, нам также нужно добавить обработчик событий к нашей кнопке "выполнить", чтобы она действительно что-то делала:


```js
document.querySelector(".runButton").addEventListener("click", play, false);
```

### Результат

Остановка анимации
------------------

Простое удаление `animation-name` применённого к элементу, заставит его исчезнуть или перейти в следующее состояние. Если вместо этого вы хотите, чтобы анимация закончилась, а затем остановилась, вам нужно попробовать другой подход. Главные хитрости заключаются в следующем:

1. Сделайте свою анимацию настолько самодостаточной, насколько это возможно. Это означает, что вы не должны полагаться на `animation-direction: alternate`. Вместо этого вы должны явно написать анимацию ключевого кадра, которая проходит через полную анимацию в одном прямом повторении.
2. Используйте JavaScript и очистите анимацию, используемую при запуске события `animationiteration`.

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


```css
.slidein {
  animation-duration: 5s;
  animation-name: slidein;
  animation-iteration-count: infinite;
}

.stopped {
  animation-name: none;
}

@keyframes slidein {
  0% {
    margin-left: 0%;
  }
  50% {
    margin-left: 50%;
  }
  100% {
    margin-left: 0%;
  }
}
```



```html
<h1 id="watchme">Click me to stop</h1>
```



```js
let watchme = document.getElementById("watchme");

watchme.className = "slidein";
const listener = (e) => {
  watchme.className = "slidein stopped";
};
watchme.addEventListener("click", () =>
  watchme.addEventListener("animationiteration", listener, false),
);
```


Demo https://jsfiddle.net/morenoh149/5ty5a4oy/

Смотрите также
--------------

* Using CSS transitions (en-US)
* `Window.requestAnimationFrame()`