Красивая анимация — это ощущение качества интерфейса. Но та же анимация, сделанная неправильно, превращается в рывки, просадку FPS и «залипающую» прокрутку, особенно на бюджетных телефонах. Разница между плавным и дёрганым эффектом почти всегда не в дизайне, а в том, какие CSS-свойства анимируются и как браузер их обрабатывает.
Эта статья — инженерный разбор того, как делать анимации без потери производительности: как устроен конвейер рендеринга, почему transform и opacity дешёвые, а left и width дорогие, что реально делает will-change и как всё это не ломает Core Web Vitals. Тема тесно связана со скоростью в целом — её мы разбираем в статье про инфраструктуру на BitrixVM, а системную оптимизацию закрывает аудит и оптимизация 1С.
Коротко
- Анимируйте
transformиopacity— они идут через композитинг на GPU, минуя дорогие layout и paint. - Избегайте анимации
left,top,width,height— они вызывают пересчёт геометрии на каждом кадре. will-change— подсказка браузеру, а не ускоритель; применяйте точечно и снимайте после анимации.- Держите бюджет ~16 мс на кадр (60 FPS), не блокируйте главный поток и уважайте
prefers-reduced-motion.
Почему анимации тормозят
Плавность анимации определяется тем, успевает ли браузер отрисовать каждый кадр вовремя. При 60 кадрах в секунду на один кадр есть около 16 миллисекунд, и в этот бюджет должна уложиться вся работа: пересчёт стилей, геометрии, отрисовка и сборка слоёв. Если не укладывается — кадр пропускается, и глаз видит рывок (jank).
Главная причина тормозов — анимация «дорогих» свойств, которые на каждом кадре заставляют браузер заново считать положение элементов и перерисовывать пиксели. Визуально результат может выглядеть так же, как у «дешёвой» анимации, но нагрузка отличается в разы. Понимание того, какая работа стоит за каждым свойством, — ключ к плавным анимациям.
Конвейер рендеринга: layout, paint, composite
Чтобы показать кадр, браузер проходит несколько стадий. Упрощённо:
- Style. Вычисление итоговых стилей элементов.
- Layout. Расчёт геометрии — где и какого размера каждый элемент. Дорогая стадия: меняется один элемент — пересчитываются связанные.
- Paint. Отрисовка пикселей элементов в слои — заливки, текст, тени.
- Composite. Сборка готовых слоёв в финальную картинку, часто силами GPU. Самая дешёвая стадия.
Суть оптимизации анимаций — заставить браузер на каждом кадре делать как можно меньше стадий. Идеал — когда анимация затрагивает только composite, пропуская layout и paint. Именно это даёт максимально плавный результат при минимальной нагрузке.
Дешёвые и дорогие свойства для анимации
| Свойство | Какие стадии запускает | Стоимость |
|---|---|---|
transform (translate, scale, rotate) | Только composite | Дёшево |
opacity | Только composite | Дёшево |
left, top, margin | Layout + paint + composite | Дорого |
width, height | Layout + paint + composite | Дорого |
box-shadow, background | Paint + composite | Средне-дорого |
color | Paint + composite | Средне |
Практический вывод простой: перемещение делайте через transform: translate(), а не через left/top; масштабирование — через transform: scale(), а не через width/height; появление и исчезновение — через opacity. Тот же визуальный эффект, но в разы дешевле для браузера.
GPU и композитные слои
Почему transform и opacity такие дешёвые? Потому что анимируемый элемент выносится на отдельный композитный слой — независимый «холст», который браузер может двигать и накладывать силами GPU, не перерисовывая соседей. Перемещение такого слоя — это просто пересборка картинки из готовых кусков, без пересчёта геометрии и повторной отрисовки.
Слои создаются автоматически для transform/opacity-анимаций или по подсказке will-change. Но у слоёв есть цена — память: каждый слой занимает видеопамять. Поэтому нельзя выносить на отдельные слои всё подряд: сотни слоёв «съедят» память и на слабом устройстве сделают только хуже. Баланс — выносить на слои именно то, что анимируется, и не больше.
Как правильно применять will-change
will-change заранее сообщает браузеру, что элемент будет меняться, чтобы тот подготовил композитный слой и убрал микроподтормаживание в самом начале анимации. Это полезный инструмент, но его массово переоценивают и неправильно используют.
Правила применения:
- Точечно, а не глобально. Не вешайте
will-changeна «всё, что шевелится» — это перерасход памяти. - К конкретным свойствам. Указывайте, что именно изменится:
will-change: transform, а не абстрактное «всё». - Незадолго до анимации. В идеале добавлять перед началом и снимать после — но без частого дёрганья, которое само по себе стоит ресурсов.
- Не как ускоритель. Это подсказка, а не «турбо-кнопка»; неправильное применение ухудшает производительность.
На практике для многих CSS-анимаций will-change вообще не нужен: браузер и так создаёт слой под transform/opacity. Добавляйте его только там, где действительно видите подтормаживание в начале анимации.
Бюджет кадра и 60 FPS
Плавность измеряется в кадрах в секунду. Стандарт — 60 FPS, то есть ~16 мс на кадр на всю работу браузера. На экранах 90 и 120 Гц бюджет ещё жёстче — около 11 и 8 мс. Выход за бюджет означает пропущенные кадры и видимые рывки.
Чтобы укладываться в бюджет, важно не только анимировать дешёвые свойства, но и не занимать главный поток другой работой во время анимации. Тяжёлый JavaScript, синхронные вычисления, реакции на скролл — всё это конкурирует за те же миллисекунды. Особенно это критично на длинных списках товаров в каталоге, где к прокрутке добавляются эффекты появления карточек.
Анимации на JavaScript без рывков
Иногда анимацию удобнее делать на JS — но именно здесь легче всего получить рывки. Ключевые правила:
- requestAnimationFrame. Синхронизируйте изменения с кадрами браузера через
requestAnimationFrame, а не черезsetInterval. - Не смешивайте чтение и запись. Чтение геометрии (
offsetWidth,getBoundingClientRect) вперемешку с изменением стилей вызывает принудительные пересчёты layout (layout thrashing) и рывки. - Анимируйте transform/opacity. Даже в JS меняйте дешёвые свойства, а не геометрию.
- Выносите тяжёлое из кадра. Сложные вычисления — вне анимационного цикла, чтобы не съедать бюджет кадра.
Для сложных сцен часто надёжнее и дешевле обычные CSS-анимации и переходы — браузер оптимизирует их лучше, чем ручной JS. К ручному JS прибегают, когда нужна логика, которую CSS не выражает.
Влияние на Core Web Vitals
Анимации связаны с метриками качества страницы, и связь эта двоякая. Неправильные анимации портят метрики:
- CLS. Анимация, сдвигающая контент (появляющиеся блоки, «прыгающие» элементы), увеличивает Cumulative Layout Shift.
- INP. Тяжёлый анимационный JavaScript блокирует главный поток, и интерфейс медленно откликается на действия.
При этом правильно сделанные композитные анимации transform/opacity почти не нагружают главный поток и на метрики практически не влияют. Вывод: анимация не враг производительности сама по себе — вредит именно неправильная реализация. Как метрики устроены в целом и как их держать в зелёной зоне, тесно связано со стеком D7 и архитектурой — об этом в статье про D7 и ORM в Битрикс.
Доступность и prefers-reduced-motion
Не все хотят видеть движение. Часть пользователей включает системную настройку уменьшения движения — по медицинским причинам (вестибулярные нарушения) или просто по предпочтению. Уважать её обязательно через медиазапрос prefers-reduced-motion.
При его активации крупные перемещения, параллаксы, автопрокрутки и резкие эффекты отключают или сильно упрощают, оставляя максимум мягкие переходы прозрачности. Ключевое правило: интерфейс должен оставаться полностью функциональным без анимаций — они украшают, но не несут смысла, без которого нельзя пользоваться сайтом. Это одновременно и доступность, и хороший инженерный тон.
Анимации в шаблонах 1С-Битрикс
На 1С-Битрикс анимации живут в CSS и JS шаблонов компонентов и общего шаблона сайта. Сами по себе они не мешают работе компонентов — проблемы начинаются, когда эффекты навешивают неаккуратно на нагруженные части витрины:
- Каталог и списки. Тяжёлые эффекты появления на длинном списке товаров дают просадку при прокрутке — здесь минимум анимаций и только композитные свойства.
- Умный фильтр. Раскрытия и переходы в
catalog.smart.filterдолжны быть лёгкими, чтобы не тормозить и без того нагруженную выдачу. - Модальные окна и меню. Хорошие кандидаты на transform/opacity-анимации — они изолированы и не трогают геометрию списка.
- Карточка товара. Галерея и переключение вариантов — плавно, но без блокировки главного потока.
Правильный подход — лёгкие композитные анимации, уважение к производительности каталога и проверка на реальных устройствах, а не только на мощной машине разработчика.
Как измерять производительность анимаций
Плавность нельзя оценивать «на глаз» на мощном ноутбуке — нужно измерять на условиях аудитории:
- Панель Performance в DevTools. Записывает кадры и показывает, какие стадии (layout, paint, composite) выполняются и где рывки.
- FPS-метр. Индикатор частоты кадров при прокрутке и взаимодействии.
- Троттлинг CPU. Эмуляция медленного процессора, чтобы увидеть анимации глазами владельца бюджетного телефона.
- Слои (Layers). Панель, показывающая композитные слои и их количество — чтобы не расплодить лишние.
Главный принцип тот же, что и с Core Web Vitals: тестируйте на слабом устройстве, а не там, где «и так всё летает».
Частые ошибки
- Анимация left/top/width. Дорогие свойства вызывают layout на каждом кадре — прямой путь к рывкам.
- will-change на всём подряд. Перерасход памяти вместо ускорения.
- Слишком много слоёв. Сотни композитных слоёв «съедают» видеопамять.
- Layout thrashing в JS. Чтение геометрии вперемешку с записью стилей в цикле анимации.
- setInterval вместо rAF. Рассинхрон с кадрами браузера и дёрганье.
- Тяжёлый JS во время анимации. Блокировка главного потока и падение INP.
- Игнор prefers-reduced-motion. Анимации навязаны тем, кому они мешают.
- Проверка только на мощной машине. На бюджетном телефоне всё тормозит, а разработчик этого не видит.
Чек-лист внедрения
- Анимируются дешёвые свойства. Перемещение и масштаб — через transform, появление — через opacity.
- Дорогие свойства убраны. Нет анимаций left/top/width/height в критичных местах.
- will-change точечный. Применён к конкретным элементам и свойствам, снимается после анимации.
- Слои под контролем. Композитных слоёв ровно столько, сколько нужно.
- JS-анимации через rAF. Нет layout thrashing, нет setInterval.
- Метрики не страдают. Анимации не создают CLS и не роняют INP.
- Reduced motion уважается. При системной настройке анимации упрощаются или отключаются.
- Проверено на слабом устройстве. FPS стабилен при троттлинге CPU и на бюджетном телефоне.
Вывод
Плавная анимация — это не про «больше эффектов», а про понимание того, какую работу браузер делает на каждом кадре. Секрет прост: анимируйте transform и opacity, которые идут через композитинг на GPU, и избегайте дорогих свойств, вызывающих пересчёт геометрии. Тогда тот же визуальный эффект укладывается в бюджет кадра без рывков.
will-change — тонкий инструмент, а не ускоритель: применяйте его точечно и снимайте после анимации. Держите число композитных слоёв разумным, не блокируйте главный поток тяжёлым JS, уважайте prefers-reduced-motion и всегда проверяйте на слабом устройстве, а не на своей мощной машине. Тогда анимации на сайте 1С-Битрикс будут украшать интерфейс, а не портить производительность и Core Web Vitals. Системно навести порядок во фронтенде поможет аудит и оптимизация 1С.