Производительность анимаций
Плавность анимации зависит не от её красоты, а от того, какие свойства вы анимируете и сколько работы это даёт браузеру на каждом кадре.
Композиторная анимация — это анимация только тех свойств, которые браузер может проиграть на отдельном слое, не пересчитывая раскладку и отрисовку страницы.
Чтобы движение выглядело гладким, браузер должен успевать рисовать кадр за ~16 мс (60 кадров в секунду). Если на кадр приходится слишком много работы, кадры «проседают» — анимация дёргается (это называют jank). Главный рычаг борьбы с этим — выбор анимируемого свойства.
Конвейер рендеринга: три этапа
Каждый кадр браузер потенциально проходит три дорожающих этапа:
- Layout (раскладка) — вычисление геометрии: где и какого размера каждый элемент. Меняется при анимации
width,height,top,margin,padding. - Paint (отрисовка) — заливка пикселей: цвета, тени, границы. Меняется при анимации
background-color,box-shadow,color. - Composite (композиция) — склейка готовых слоёв на экране. Сюда попадают
transformиopacity.
Чем раньше этап, тем он дороже и тем больше тянет за собой: изменение Layout вынуждает заново сделать Paint и Composite. А анимация на этапе Composite не трогает первые два — поэтому она самая дешёвая.
Дёшево: transform и opacity
Эти два свойства браузер умеет анимировать целиком на этапе композиции, часто силами видеокарты, не перерисовывая содержимое. Практически любое «дорогое» движение можно переписать через них.
| Дорогой способ | Дешёвая замена |
left / top | transform: translate(...) |
width / height | transform: scale(...) |
visibility + перерисовка | opacity |
/* Дорого: каждый кадр — пересчёт раскладки */
.bad {
transition: left 0.3s, width 0.3s;
}
/* Дёшево: только композиция */
.good {
transition: transform 0.3s, opacity 0.3s;
}
Дорого: layout-свойства
Анимация размеров и позиции через layout-свойства запускает пересчёт раскладки на каждом кадре. Для одного маленького блока это незаметно, но если внутри много содержимого или элементов на странице сотни, кадры проседают. Особенно коварна анимация box-shadow: она вызывает дорогой повторный Paint. Часто тень имитируют отдельным псевдоэлементом, у которого анимируют opacity.
will-change: подсказка браузеру
Свойство will-change заранее сообщает браузеру, что элемент скоро будет меняться, — и тот может вынести его на отдельный композиторный слой до начала анимации, избежав рывка на первом кадре.
.card {
transition: transform 0.2s;
}
.list:hover .card {
will-change: transform;
transform: translateY(-4px);
}
Но will-change — не «кнопка ускорения». Каждый слой стоит памяти; если повесить его на десятки элементов навсегда, станет хуже, а не лучше. Правила: применяйте точечно, в идеале незадолго до анимации (например, по :hover родителя), и не оставляйте на постоянной основе на множестве элементов.
Слои композитора
Браузер может вынести элемент на собственный слой (как прозрачную плёнку поверх остальной страницы). Анимация transform/opacity такого слоя сводится к сдвигу и смешиванию готовой картинки — это умеет делать GPU очень быстро. На слой элемент попадает по разным причинам: анимация transform/opacity, will-change, иногда position: fixed или видео. В панели Layers/Rendering браузерных DevTools слои видно, и там же можно проверить, не плодите ли вы их слишком много.
prefers-reduced-motion: доступность
Для части людей анимации — не украшение, а проблема: интенсивное движение, параллаксы и зумы могут вызывать головокружение, тошноту и приступы у людей с вестибулярными расстройствами. В системных настройках есть переключатель «уменьшить движение», и его значение доступно в CSS через медиазапрос. Уважать его — обязательная часть доступного интерфейса.
.banner {
animation: slide-in 0.5s ease-out;
}
@media (prefers-reduced-motion: reduce) {
.banner {
animation: none; /* показать сразу, без движения */
}
* {
transition-duration: 0.01ms !important;
}
}
Хороший тон — не выключать интерфейс полностью, а заменять крупные перемещения на мгновенное появление или лёгкое затухание opacity: смысл анимации (что-то изменилось) сохраняется, а дискомфортное движение убирается.
Как это измерить
Не угадывайте «на глаз». В DevTools есть вкладка Performance: запишите анимацию и посмотрите на полосу FPS и на длинные задачи главного потока — частые жёлтые блоки Layout/Recalculate Style выдают дорогую анимацию. Панель Rendering умеет включить счётчик FPS и подсветку перерисовываемых областей (Paint flashing): если при движении мигает половина экрана, вы анимируете не то свойство. Эти инструменты быстро показывают, действительно ли ваша анимация осталась на этапе композиции.
Как это работает под капотом
На каждый кадр главный поток браузера решает, какие этапы конвейера нужно повторить из-за изменившихся свойств. Если изменился только transform или opacity элемента, лежащего на своём слое, главный поток почти не задействован — кадр собирает композитор (часто на GPU), и анимация остаётся плавной, даже если JavaScript занят. Если же изменилось layout-свойство, главный поток обязан заново посчитать раскладку всей затронутой части дерева, потом Paint, потом Composite — и при нехватке времени кадр пропускается.
Частые ошибки
- Анимация
top/left/widthвместоtransform. Первый же кандидат на jank. will-changeна всех элементах подряд и навсегда. Лишние слои съедают память и замедляют страницу.- Анимация
box-shadowв цикле. Дорогой повторный Paint; имитируйте тень черезopacityпсевдоэлемента. - Игнорирование
prefers-reduced-motion. Интерфейс становится недоступным для части пользователей.
Итоги
- Кадр проходит этапы Layout → Paint → Composite; ранние этапы дороже.
- Дёшево анимировать
transformиopacity— они живут на этапе композиции. - Layout-свойства (
width,top,margin) иbox-shadowв анимации дороги. will-changeготовит слой заранее, но применяйте его точечно.prefers-reduced-motion— обязательная забота о доступности: уменьшайте движение по запросу.