Как делать анимацию через JavaScript?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как делать анимацию через JavaScript
Анимация через JavaScript — это мощный способ создания интерактивных и динамичных интерфейсов. Я покажу несколько методов от простых к сложным.
1. setTimeout и setInterval (Базовый способ)
Минусы: плохо для производительности, непредсказуем
// Плохой пример - не используй
let position = 0;
const interval = setInterval(() => {
position += 1;
element.style.left = position + 'px';
if (position >= 100) {
clearInterval(interval);
}
}, 16); // ~60fps (1000/60 = ~16ms)
Проблемы:
- Не синхронизирован с браузером (может пропустить кадры)
- Продолжает работать, даже если tab не активный
- Плохая производительность
2. requestAnimationFrame (RAF) — Рекомендуется
Это синхронизировано с браузером (идеально для анимаций)
// Хороший пример
let position = 0;
const startTime = Date.now();
const duration = 1000; // 1 секунда
function animate() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
position = progress * 100; // 0 -> 100
element.style.left = position + 'px';
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
Плюсы RAF:
- Синхронизирован с браузером (60fps или 120fps)
- Паузится когда tab не активный
- Оптимален для производительности
- Браузер может оптимизировать
3. CSS Transitions и Animations (Самый простой способ)
Для простых анимаций — лучше использовать CSS
CSS Transitions
// JavaScript только триггерит, CSS делает работу
const element = document.querySelector('.box');
// Добавляем класс
element.classList.add('slide'); // Transition произойдёт
// CSS
style = `
.box {
position: relative;
transition: all 0.3s ease; /* Браузер оптимизирует */
}
.box.slide {
left: 100px;
}
`;
CSS Animations
const element = document.querySelector('.box');
element.classList.add('bounce'); // Запускает анимацию
// CSS
style = `
@keyframes bounce {
0% { transform: translateY(0); }
50% { transform: translateY(-20px); }
100% { transform: translateY(0); }
}
.box.bounce {
animation: bounce 0.5s ease;
}
`;
4. Easing функции (Плавность анимации)
Без easing анимация выглядит неестественно
// Линейная (монотонная)
function easeLinear(progress) {
return progress;
}
// Ease-in (медленно ускоряется)
function easeInQuad(progress) {
return progress * progress;
}
// Ease-out (быстро замедляется)
function easeOutQuad(progress) {
return progress * (2 - progress);
}
// Ease-in-out (медленно разгоняется и останавливается)
function easeInOutQuad(progress) {
return progress < 0.5
? 2 * progress * progress
: -1 + (4 - 2 * progress) * progress;
}
// Использование
function animate(duration, easing, callback) {
const startTime = Date.now();
function frame() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
const easedProgress = easing(progress);
callback(easedProgress);
if (progress < 1) {
requestAnimationFrame(frame);
}
}
requestAnimationFrame(frame);
}
// Применение
animate(1000, easeOutQuad, (progress) => {
element.style.left = (progress * 100) + 'px';
});
5. Web Animations API (Современный способ)
Объединяет лучшее от JS и CSS
const element = document.querySelector('.box');
// Определяем keyframes
const keyframes = [
{ transform: 'translateX(0)', offset: 0 },
{ transform: 'translateX(100px)', offset: 1 }
];
// Опции анимации
const options = {
duration: 1000, // 1 секунда
easing: 'ease-out', // встроенные easing функции
fill: 'forwards', // остаются ли стили после
iterations: 1 // количество повторений
};
const animation = element.animate(keyframes, options);
// События
animation.onfinish = () => console.log('Done!');
animation.oncancel = () => console.log('Cancelled');
// Управление
animation.pause();
animation.play();
animation.reverse();
animation.playbackRate = 2; // 2x скорость
6. Spring Анимация (Реалистичная физика)
Используется в современном UI (iOS, Material Design)
class SpringAnimation {
constructor(stiffness = 0.1, damping = 0.8) {
this.stiffness = stiffness; // Жесткость пружины
this.damping = damping; // Трение
this.velocity = 0;
}
update(current, target) {
const distance = target - current;
const force = distance * this.stiffness;
this.velocity += force;
this.velocity *= this.damping; // Применяем трение
return current + this.velocity;
}
}
// Использование
const spring = new SpringAnimation();
let value = 0;
const target = 100;
function frame() {
value = spring.update(value, target);
element.style.left = value + 'px';
if (Math.abs(target - value) > 0.1) {
requestAnimationFrame(frame);
} else {
element.style.left = target + 'px';
}
}
requestAnimationFrame(frame);
7. Практический пример: React компонент с анимацией
import { useEffect, useRef } from 'react';
function AnimatedBox() {
const boxRef = useRef(null);
useEffect(() => {
if (!boxRef.current) return;
const element = boxRef.current;
const startTime = Date.now();
const duration = 1000;
function animate() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
const easing = progress * (2 - progress); // ease-out
element.style.transform = `translateX(${easing * 100}px)`;
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
}, []);
return (
<div
ref={boxRef}
style={{
width: '50px',
height: '50px',
backgroundColor: 'blue',
position: 'relative'
}}
/>
);
}
8. Морфинг (Морфирование форм)
// SVG морфинг
const svg = document.querySelector('path');
const startPath = 'M10 10 L100 10 L100 100 Z'; // Треугольник
const endPath = 'M50 10 A40 40 0 0 1 50 90 A40 40 0 0 1 50 10'; // Круг
function morphPath(progress) {
// Интерполируем между двумя path'ами
// Это сложнее, используй библиотеку
}
9. Рекомендуемые библиотеки
GSAP (GreenSock Animation Platform)
import gsap from 'gsap';
// Анимирует свойство от 0 к 100
gsap.to(element, {
duration: 1,
left: 100,
opacity: 0.5,
ease: 'power2.out',
onComplete: () => console.log('Done')
});
Framer Motion (для React)
import { motion } from 'framer-motion';
export function AnimatedBox() {
return (
<motion.div
initial={{ x: 0 }}
animate={{ x: 100 }}
transition={{ duration: 1, ease: 'easeOut' }}
/>
);
}
React Spring
import { useSpring, animated } from '@react-spring/web';
export function AnimatedBox() {
const springs = useSpring({
from: { x: 0 },
to: { x: 100 },
config: { tension: 300, friction: 60 }
});
return <animated.div style={springs} />;
}
Когда использовать каждый метод:
| Метод | Когда использовать | Производительность |
|---|---|---|
| CSS Transitions | Простые изменения состояния | Отличная |
| CSS Animations | Циклические анимации | Отличная |
| requestAnimationFrame | Комплексная логика | Хорошая |
| Web Animations API | Средняя сложность | Отличная |
| GSAP | Профессиональные анимации | Отличная |
| Framer Motion | React проекты | Хорошая |
| setTimeout/setInterval | НИКОГДА! | Плохая |
Лучшие практики:
1. Используй transform и opacity для анимаций
// Хорошо - браузер оптимизирует
element.style.transform = 'translateX(100px)';
element.style.opacity = 0.5;
// Плохо - вызывает reflow
element.style.left = '100px';
element.style.width = '100px';
2. Отключай анимации для пользователей с prefers-reduced-motion
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!prefersReduced) {
// Запускай анимацию
}
3. Используй will-change для подсказки браузеру
element.style.willChange = 'transform';
// Анимируй...
element.style.willChange = 'auto'; // Отключи когда готово
Итоговый ответ:
Для анимаций через JavaScript:
- Начни с CSS (transitions/animations)
- Если нужна сложная логика, используй requestAnimationFrame
- Для React используй Framer Motion или React Spring
- Для профессиональных анимаций используй GSAP
- Никогда не используй setTimeout/setInterval для анимаций
Оптимизируй производительность: используй transform/opacity, избегай изменений layout.