Разбираем способы анимаций на 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 секунды плавно, без рывков.