Анимации на сайте: CSS или JavaScript, GSAP и Motion
Практика3 минРедакция Innovialabs
Коротко
Простые состояния (hover, появление, раскрытие) делайте на CSS, сложные последовательности и анимации по прокрутке — на GSAP или Motion; анимируйте только transform и opacity и отключайте движение при prefers-reduced-motion.
Короткий ответ
- CSS transitions и keyframes — для hover, фокуса, открытия меню, появления элементов, бесконечных лоадеров. Это дёшево, не требует библиотек и работает даже до загрузки JavaScript.
- GSAP — для сложных таймлайнов, синхронизации многих элементов, анимаций по прокрутке с закреплением блоков, анимации SVG.
- Motion — для React-интерфейсов: анимации появления и исчезновения компонентов, перестановки в списках, жесты, переходы между состояниями. Есть и версия для обычного JavaScript.
Правило выбора простое: если анимацию можно описать как «из состояния А в состояние Б по событию», берите CSS. Если нужны цепочки, управление временем, привязка к прокрутке или физика — JavaScript-библиотеку.
Какие свойства анимировать дёшево
Браузер рисует кадр в несколько этапов: layout (расчёт размеров), paint (отрисовка пикселей) и composite (склейка слоёв). Чем раньше этап затрагивает анимация, тем она дороже.
| Свойство | Что пересчитывается | Цена |
|---|---|---|
transform, opacity | только composite | дёшево |
color, background-color, box-shadow | paint | средне |
width, height, top, left, margin, padding | layout + paint | дорого |
Вместо left используйте transform: translateX(), вместо width — transform: scale(). Тень дешевле анимировать через opacity псевдоэлемента с готовой тенью.
will-change: transform подсказывает браузеру вынести элемент в отдельный слой. Ставьте его точечно и только на то, что действительно анимируется: лишние слои расходуют память.
CSS: когда его хватает
.card {
transition: transform 200ms ease, opacity 200ms ease;
}
.card:hover {
transform: translateY(-4px);
}
@media (prefers-reduced-motion: reduce) {
.card { transition: none; }
.card:hover { transform: none; }
}
Для анимаций при прокрутке в современных браузерах появились scroll-driven animations (animation-timeline: view()), которые работают без JavaScript. Поддержка пока неполная, поэтому проверяйте её и делайте так, чтобы без анимации контент оставался видимым.
GSAP и Motion: анимации по прокрутке
Простое появление при прокрутке можно сделать через Intersection Observer и CSS-класс. Если нужны закрепление секции, анимация, привязанная к положению прокрутки, или сложная последовательность, удобнее библиотека.
GSAP с плагином ScrollTrigger и учётом настроек пользователя:
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
const mm = gsap.matchMedia();
mm.add("(prefers-reduced-motion: no-preference)", () => {
gsap.from(".feature", {
y: 40,
opacity: 0,
stagger: 0.1,
scrollTrigger: { trigger: ".features", start: "top 80%" }
});
});
Motion в React:
import { motion, MotionConfig } from "motion/react";
<MotionConfig reducedMotion="user">
<motion.div
initial={{ opacity: 0, y: 24 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
/>
</MotionConfig>
reducedMotion="user" отключает анимацию трансформаций у тех, кто включил уменьшение движения в системе.
prefers-reduced-motion
У части людей движение на экране вызывает головокружение и тошноту. Медиазапрос prefers-reduced-motion сообщает, что пользователь попросил систему уменьшить анимации. Что делать:
- убирать параллакс, крупные перемещения и автопрокрутку;
- оставлять короткие изменения прозрачности и цвета — они обычно не мешают;
- следить, чтобы контент без анимации был сразу видим, а не застревал в
opacity: 0.
Как избежать рывков
- Анимируйте transform и opacity, а не размеры и отступы.
- Не читайте и не меняйте размеры в одном цикле (
offsetHeight, затем запись стиля, затем снова чтение) — это вызывает принудительный пересчёт layout. - JavaScript-анимации делайте через
requestAnimationFrameили библиотеку, а не черезsetInterval. - Не вешайте тяжёлую логику на событие
scroll. - Проверяйте на слабом телефоне и в панели Performance в DevTools с замедлением CPU.
- Не анимируйте всё подряд: одна выразительная анимация лучше десяти мелких.