Разбираем способы анимаций на JavaScript

Раздел: Анимации -> Анимации в JavaScript

Техники анимации в веб-разработке

Как реализовать анимацию, управляемую JavaScript, с максимальной производительностью?

Основным и наиболее производительным способом является использование CSS @keyframes с переключением классов через JavaScript. Такой подход позволяет браузеру оптимизировать анимацию на GPU, освобождая основной поток. Подходит для типовых сценариев: появление элементов, переходы между состояниями, простые движения.

Пример: анимация появления блока с opacity и transform.


/* CSS */
@keyframes fadeSlide {
  from { opacity: 0; transform: translateY(-20px); }
  to { opacity: 1; transform: translateY(0); }
}
.animate-in {
  animation: fadeSlide 0.4s ease-out forwards;
}

/* JavaScript */
const element = document.querySelector('.box');
element.classList.add('animate-in');

Js анимации (анимации в javascript)

Результат: при добавлении класса элемент плавно появляется со смещением снизу за 0.4 секунды.

Возможные проблемы: анимация перестаёт работать, если не указать forwards (элемент возвращается в исходное состояние). Типичная ошибка – забыть удалить класс после завершения для повторного воспроизведения. Для повторного запуска требуется сначала удалить класс, затем через requestAnimationFrame добавить снова.

Как вручную управлять анимацией, обновляя состояние в каждом кадре?

Метод requestAnimationFrame (rAF) даёт полный контроль над анимацией, выполняя функцию до перерисовки страницы. Подходит для сложных траекторий, физических симуляций, игр.


function animate() {
  const box = document.getElementById('box');
  let position = 0;
  const duration = 2000; // мс
  const start = performance.now();
  
  function step(now) {
    const elapsed = now - start;
    const progress = Math.min(elapsed / duration, 1);
    position = 300 * progress; // движение на 300px
    box.style.transform = `translateX(${position}px)`;
    if (progress < 1) requestAnimationFrame(step);
  }
  
  requestAnimationFrame(step);
}
Результат: элемент плавно перемещается вправо на 300px за 2 секунды. Анимация останавливается по достижении финальной позиции.

Ошибки: неправильный расчёт времени – если performance.now() вызывается внутри step, а не один раз, анимация может дергаться. Забыть проверку progress < 1 приводит к бесконечному вызову. Стоит избегать анимации свойств, вызывающих перекомпоновку (например, left, top).

Как создавать сложные цепочки анимаций с минимальным кодом?

Библиотека GSAP (GreenSock Animation Platform) предоставляет мощный движок для последовательностей, параллельных анимаций и управления временем. Используется для лендингов, презентаций, UI.


import gsap from 'gsap';

gsap.to('.box', {
  x: 200,
  duration: 1,
  ease: 'power2.inOut',
  delay: 0.5,
  onComplete: () => console.log('Завершено')
});

gsap.from('.title', { opacity: 0, y: -30, duration: 0.6 });
Результат: элемент с классом box смещается на 200px по оси X за 1 секунду с задержкой, а заголовок title появляется сверху.

Проблемы: подключение библиотеки увеличивает размер страницы. Ошибки при игнорировании ease – анимация может выглядеть неестественно. GSAP требует внимательного чтения документации для работы с timeline и обратными вызовами.

Как нативно анимировать элементы с помощью JavaScript, не прибегая к сторонним библиотекам?

Web Animations API (WAAPI) – встроенный интерфейс, позволяющий управлять анимациями из JS. Поддерживает паузу, реверс, смену скорости. Идеален для простых динамических анимаций без дополнительных зависимостей.


const box = document.querySelector('.box');
const animation = box.animate([
  { transform: 'translateX(0px)' },
  { transform: 'translateX(150px)', offset: 0.7 },
  { transform: 'translateX(200px)' }
], {
  duration: 2000,
  iterations: 2,
  direction: 'alternate',
  easing: 'ease-in-out'
});

// управление
animation.pause();
setTimeout(() => animation.play(), 1000);
Результат: элемент движется вправо на 200px с промежуточной точкой на 150px, повторяется дважды с возвратом. Через 1 секунду анимация запускается после паузы.

Ошибки: несовместимость со старыми браузерами – требуется полифилл. Неправильная настройка offset (от 0 до 1) ломает временную шкалу. Свойство fill по умолчанию none, поэтому после окончания элемент возвращается в исходное состояние, если не указать fill: 'forwards'.

Расширенные примеры анимаций на JavaScript

Пример 1: CSS @keyframes с динамическим управлением

Создание последовательности: элемент исчезает, затем появляется с другого места.

Пример

/* CSS */
@keyframes fadeOut {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(0.5); }
}
@keyframes fadeInFromRight {
  from { opacity: 0; transform: translateX(100px); }
  to   { opacity: 1; transform: translateX(0); }
}
.fade-out {
  animation: fadeOut 0.5s ease-in forwards;
}
.fade-in-right {
  animation: fadeInFromRight 0.5s ease-out forwards;
}

// JavaScript - добавляем классы с таймингом
const box = document.querySelector('.box');
box.classList.add('fade-out');
setTimeout(() => {
  box.classList.remove('fade-out');
  box.classList.add('fade-in-right');
}, 600);
Результат: блок уменьшается и исчезает за 0.5 с, затем через 0.6 с появляется справа с увеличением прозрачности.

Пример 2: requestAnimationFrame с функцией плавности (easing)

Реализация кастомного easing для движения по кривой.

Пример

function easeOutCubic(t) {
  return 1 - Math.pow(1 - t, 3);
}

function animateWithEasing(element, targetX, duration) {
  const startX = 0;
  const startTime = performance.now();
  function step(currentTime) {
    const elapsed = currentTime - startTime;
    const progress = Math.min(elapsed / duration, 1);
    const easedProgress = easeOutCubic(progress);
    const currentX = startX + (targetX - startX) * easedProgress;
    element.style.transform = `translateX(${currentX}px)`;
    if (progress < 1) requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
}

const box = document.querySelector('.box');
animateWithEasing(box, 400, 2000);
Результат: элемент движется вправо на 400 пикселей за 2 секунды с замедлением в конце (cubic ease-out).

Пример 3: GSAP Timeline для сложной последовательности

Анимация нескольких элементов с наложением и задержками.

Пример

const tl = gsap.timeline({ repeat: 1, yoyo: true, ease: 'power1.inOut' });
tl.to('.box1', { x: 100, duration: 0.5 })
  .to('.box2', { x: 100, duration: 0.5 }, '-=0.3') // наложение
  .to('.box3', { opacity: 0, duration: 0.3 }, '+=0.2');
Результат: три блока двигаются с перекрытием. Сначала box1, затем через 0.3 с (параллельно) box2, и через 0.2 с после box2 исчезает box3. Повторяется с реверсом.

Пример 4: Web Animations API с управлением playback

Создание анимации с возможностью паузы, перемотки и реверса.

Пример

const el = document.querySelector('.animated-element');
const anim = el.animate([
  { transform: 'rotate(0deg)', background: 'blue' },
  { transform: 'rotate(360deg)', background: 'red' }
], {
  duration: 3000,
  iterations: Infinity
});

// Кнопки управления
playBtn.onclick = () => anim.play();
pauseBtn.onclick = () => anim.pause();
reverseBtn.onclick = () => anim.reverse();
skipBtn.onclick = () => {
  anim.currentTime = anim.effect.getTiming().duration / 2;
}
Результат: элемент вращается и меняет цвет бесконечно. Пользователь может приостанавливать, переворачивать и перематывать на середину.

Пример 5: Комбинация CSS и requestAnimationFrame для прогресс-бара

CSS анимация ширины элемента с точным обновлением через rAF.

Пример

<div id="progress-bar" style="width:0%; height:20px; background:green;"></div>

<script>
const bar = document.getElementById('progress-bar');
let start = null;
const duration = 3000;

function animate(timestamp) {
  if (!start) start = timestamp;
  const progress = Math.min((timestamp - start) / duration, 1);
  bar.style.width = progress * 100 + '%';
  if (progress < 1) requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
</script>
Результат: зелёная полоса заполняется от 0% до 100% за 3 секунды плавно, без рывков.

Анимации в JavaScript - comments

En
Js анимации (javascript)