Как создавать веб-анимацию с помощью Anime.js

Anime.js – одна из лучших библиотек для создания анимации. Но она поставляется с минимальным объемом документации. С помощью данного руководства я попытаюсь исправить эту проблему.

Начало работы с Anime.js

Загрузите файл anime.js и подключите его в HTML-код страницы.

<script src="path/to/anime.min.js"></script>

Также можно использовать последнюю версию библиотеки:

<script src="https://cdn.jsdelivr.net/npm/animejs@3.0.1/lib/anime.min.js"></script>

Мы будем использовать функцию anime(), которая принимает объект с характеристиками анимации.

let myAnimation = anime({
  /* описание деталей анимации здесь */
});

Существует несколько видов свойств, используемых для описания анимации:

  • Targets – ссылки на элементы, которые нужно анимировать. Это может быть селектор CSS (div, #square, .rectangle), узел или список узлов DOM, объект JavaScript.
  • Properties – все свойства и атрибуты, которые можно анимировать при работе с CSS, объектами JavaScript, DOM и SVG.
  • Property Parameters–параметры, связанные со свойствами: duration, delay, easing и т. д.
  • Animation Parameters– параметры анимации: direction, loop и т. д.

Рассмотрим приведенный ниже пример:

HTML

<div></div>

CSS

div {

  width: 100px;

  height: 100px;

  background-color: green;

}

JavaScript

let animation = anime({

  targets: 'div',

  // Свойства

  translateX: 100,

  borderRadius: 50,

  // параметры свойств

  duration: 2000,

  easing: 'linear',

  // Параметры Анимации

  direction: 'alternate'

});

В приведенном выше примере мы:

  1. Выделяем зеленый квадрат (блок div).
  2. Перемещаем на 100 пикселей влево и модифицируем его в круг.
  3. Задаем период анимации в течение 2 секунд (linear означает, что к анимации не будет применено замедление).
  4. С помощью свойства direction: alternate, мы возвращаем фигуре (div) первоначальную форму. Библиотека Anime.js реализует это, воспроизводя анимацию в обратном порядке.

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

Создание анимированного маятника

В этом примере мы создадим анимацию маятника. После его отрисовки с помощью HTML и CSS пришло время вдохнуть в него жизнь.

HTML

<div id="rod">

  <div id="pivot"></div>

  <div id="ball"></div>

</div>

CSS

#rod {

  position: relative;

  margin-top: 50px;

  margin-left: 150px;

  width: 2px;

  height: 150px;

  border-radius: 5px;

  transform-origin: 50% 0%;

  transform: rotate(60deg);

  background-color: green;

}

JavaScript

let animation = anime({

  targets: '#rod',

  rotate: [60, -60], // от 60 до -60 градусов

  duration: 3000,

  easing: 'easeInOutSine',

  direction: 'alternate',

  loop: true

});  

В этой анимации мы используем from-to, который определяет диапазон движения анимации. Стержень маятника поворачивается от 60 до -60 градусов. Мы также используем значение easyInOutSine для имитации естественного замедления и ускорения маятника во время качения. А также свойство direction: 'alternate', чтобы перемещать маятник в обоих направлениях, И установили для параметра loop значение true, чтобы бесконечно повторять движение.

Создание анимации зарядки аккумулятора

Теперь создадим анимированный значок зарядки аккумулятора, который можно увидеть на смартфонах. Ниже приведен код этой анимации:

HTML

<div id="body">

<div class="segment"></div>

<div class="segment"></div>

<div class="segment"></div>

</div>

<div id="head"></div>

CSS

.segment {

  width: 0px;

  height: 25px;

  background-color: lime;

  float: left;

}

#body {

  width: 60px;

  height: 25px;

  border: solid grey 5px;

  float: left;

}

#head {

  width: 5px;

  height: 15px;

  margin-top: 10px;

  background-color: grey;

  float: left;

}

JavaScript

let animation = anime({

  targets: '.segment',

  width: 20,

  duration: 300,

  delay: function(el, i, l) {

    return i * 500;

  },

  endDelay: 500,

  easing: 'linear',

  loop: true

}); 

У нас есть три сегмента (зеленые элементы div), которые поочередно расширяются путем увеличения значения свойства width один за другим. Чтобы достичь этого эффекта, нужно использовать различные значения задержки для каждого элемента. Существует только один параметр свойства delay, который можно использовать для анимации. Поэтому применим функцию, которая создает разные значения для каждой цели.

Она принимает три аргумента: target, index и targetLength. Она возвращает индекс, умноженный на 500 миллисекунд. Это анимирует каждый элемент через полсекунды после предыдущего.

Мы также используем параметр endDelay, чтобы сделать паузу на мгновение перед запуском следующей анимации.

Улучшение анимации зарядки аккумулятора

Улучшим анимацию и добавим метку прогресса, демонстрирующую процент заряда.

HTML

<div id="body">

<div class="segment"></div>

<div class="segment"></div>

<div class="segment"></div>

</div>

<div id="head"></div>

<div id="progress"></div>

CSS

.segment {

  width: 0px;

  height: 25px;

  background-color: lime;

  float: left;

}

#body {

  width: 60px;

  height: 25px;

  border: solid grey 5px;

  float: left;

}

#head {

  width: 5px;

  height: 15px;

  margin-top: 10px;

  background-color: grey;

  float: left;

}

#progress {

  position: absolute;

  top: 12px;

  left: 90px;

  font-size: 18px;

  font-weight: bold;

}

JavaScript

let progress = document.querySelector('#progress');

let battery = {

  progress: '0%'

}

let icon = anime({

  targets: '.segment',

  width: 20,

  duration: 300,

  delay: anime.stagger(500),

  endDelay: 500,

  easing: 'linear',

  loop: true

});   

let label = anime({

  targets: battery,

  progress: '100%',

  duration: 30000,

  easing: 'linear',

  round: 1,

  update: function() {

    progress.innerHTML = battery.progress

  },

  complete: function() {

    icon.pause();

    icon.seek(icon.duration);

  } 

}); 

В этом примере используется еще несколько функций библиотеки Anime.js. Далее мы рассмотрим каждую из них.

Сначала мы создаём переменную progress, которая ссылается на элемент HTML. Затем создаем объект battery, который содержит свойство progress. После этого запускаем две анимации.

Первая анимация практически идентична предыдущему примеру, за исключением параметра delay. В ней мы будем использовать функцию anime.stagger() библиотеки Anime.js, которая позволяет анимировать сразу несколько элементов. В нашем случае она добавляет задержку в 50 миллисекунд перед анимацией каждого элемента.

Во второй анимации мы используем объект battery в качестве цели. Затем мы устанавливаем свойство progress. Параметр round округляет анимированное значение до заданного десятичного числа. Установив значение на 1, мы получаем целые числа.

Чтобы связать значение метки прогресса со значением объекта battery, мы используем функцию update(). А также функцию complete(), чтобы остановить анимацию после достижения прогресса в 100%. Метод seek() переводит анимацию в завершенное состояние.

Благодаря этому анимация зарядки будет воспроизводиться до тех пор, пока не достигнет уровня в 100%. После чего значок покажет полную зарядку батареи.

Создание более сложной анимации с помощью кейфреймов

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

HTML

<div id="box"></div>

<div id="content"></div>

CSS

div {

  width: 50px;

  height: 50px;

  top: 70px;

  left: 70px;

  background-color: green;

  position: absolute;

}

#box {

  background-color: lightgreen;

  border: solid darkorange 3px;

  margin-left: -3px;

  margin-top: -3px;

}

JavaScript

let box = document.querySelector('#box');

let animation = anime({

  targets: '#content',  

  translateY: [

    {value: 50, duration: 500},

    {value: 0, duration: 500, delay: 1500}, 

    {value: -53, duration: 500, delay: 500},

    {value: 0, duration: 500, delay: 2500},

    {value: 50, duration: 500, delay: 500},

    {value: 0, duration: 500, delay: 1500} 

  ],

  translateX: [

    {value: 53, duration: 500, delay: 1000},

    {value: 0, duration: 500, delay: 2500},

    {value: -53, duration: 500, delay: 500},

    {value: 0, duration: 500, delay: 2500}

  ],

  easing: 'linear',  

  begin: function() {

    box.style.borderBottom="none"; 

  },

  complete: function() {

    box.style.borderBottom="solid darkorange 3px";    

  }

});

Сначала мы создаем ссылку на элемент box. Мы используем его в функциях begin() и complete(), чтобы «открыть» контейнер в начале анимации и «закрыть» его в конце.

Для каждого свойства, которое будем анимировать, мы используем массив объектов. Каждый из них описывает конкретный кейфрейм.

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

Создание текстовых эффектов

В этом примере мы используем функцию stagger для создания текстового эффекта.

HTML

<h1>

<span class="letter">A</span>

<span class="letter">N</span>

<span class="letter">I</span>

<span class="letter">M</span>

<span class="letter">E</span>

<div></div>

<span class="letter">I</span>

<span class="letter">S</span>

<div></div>

<span class="letter">C</span>

<span class="letter">O</span>

<span class="letter">O</span>

<span class="letter">L</span>

<span class="letter">!</span>

</h1>

CSS

.letter {

  display: inline-block;

  opacity: 0;

}

div {

  display: inline-block;

}

JavaScript

let animation = anime({

  targets: '.letter',

  opacity: 1,

  translateY: 50,

  rotate: {

    value: 360,

    duration: 2000,

    easing: 'easeInExpo'

  },

  scale: anime.stagger([0.7, 1], {from: 'center'}),

  delay: anime.stagger(100, {start: 1000}),

  translateX: [-10, 30]

});

Мы поместили каждую букву в отдельный элемент span. Затем выделяем все буквы, делаем их видимыми и перемещаем на 50 пикселей вниз.

Затем поворачиваем буквы, определяя конкретные параметры для каждого свойства. Это дает нам больший контроль над анимацией. Буквы будут поворачиваться на 360 градусов за две секунды благодаря easyInExpo.

В следующих двух свойствах используется функция stagger(). Мы устанавливаем масштаб для равномерного увеличения от 0,7 до 1 непрозрачности, начиная с центра. Это делает буквы меньше в середине предложения и больше на обоих концах предложения.

Мы устанавливаем задержку анимации на 1 секунду (путем определения начального значения). Затем добавляем задержку в 100 миллисекунд для каждой буквы.

В конце используется свойство translateX, чтобы реализовать эффект вращения буквы по спирали.

Создание анимаций с помощью timeline()

Функция timeline() позволяет управлять одновременно несколькими анимациями. Рассмотрим простой пример.

HTML

<div class="ball one"></div>

<div class="ball two"></div>

<div class="ball three"></div>

CSS

.ball {

  width: 50px;

  height: 50px;

  margin-top: 100px;

  margin-left: 10px;

  border-radius: 50%;

  background-color: gray;

  float: left;

}

JavaScript

let animation = anime.timeline({

  duration: 1000,

  easing: 'easeInOutSine',

  direction: 'alternate', 

  loop: true

});          

animation.add({

  targets: '.one',

  translateY: -50,

  backgroundColor: 'rgb(255, 0, 0)'

}).add({

  targets: '.two',

  translateY: -50,

  backgroundColor: 'rgb(0, 255, 0)'

}).add({

  targets: '.three',

  translateY: -50,

  backgroundColor: 'rgb(0, 0, 255)'

});

В этом примере мы создаем счетчик из шариков с помощью anime.timeline(). Затем мы определяем общие параметры, которые наследуются для всех добавляемых анимаций.

Чтобы добавить анимацию, мы используем метод add(), а затем описываем ее. В данном примере мы добавляем три анимации, по одной на каждый шарик. В результате каждый шарик поднимается и опускается по очереди.

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

HTML

<div class="ball one"></div>

<div class="ball two"></div>

<div class="ball three"></div>

CSS

.ball {

  width: 50px;

  height: 50px;

  margin-top: 100px;

  margin-left: 10px;

  border-radius: 50%;

  background-color: gray;

  float: left;

}

JavaScript

let animation = anime.timeline({

  duration: 1000,

  easing: 'easeInOutSine',  

  loop: true

});          

animation.add({

  targets: '.one',

  keyframes: [

    {translateY: -50, backgroundColor: 'rgb(255, 0, 0)' },

    {translateY: 0, backgroundColor: 'rgb(128, 128, 128)'}

  ]

}).add({

  targets: '.two',

  keyframes: [

    {translateY: -50, backgroundColor: 'rgb(0, 255, 0)' },

    {translateY: 0, backgroundColor: 'rgb(128, 128, 128)'}

  ]

}, '-=900').add({

  targets: '.three',

  keyframes: [

    {translateY: -50, backgroundColor: 'rgb(0, 0, 255)' },

    {translateY: 0, backgroundColor: 'rgb(128, 128, 128)'}

  ]

}, '-=800');

В данном случае мы удаляем параметр direction, потому что используем кейфреймы для реализации движения вперед и назад. Мы определяем кейфреймы анимации, добавляя параметр keyframes. При этом каждый объект массива является кейфреймом.

Чтобы шарики двигались плавно, мы используем смещения времени, значение которого передаем в качестве второго параметра функции add().

Заключение

Я надеюсь, что вы получили более глубокое понимание Anime.js. Чтобы продолжить обучение, я рекомендую ознакомиться с официальной документацией библиотеки.

Сергей Бензенкоавтор-переводчик статьи «How to Create Web Animations with Anime.js»