Руководство по CSS-анимации: переходы, ключевые кадры и производительность
CSS-анимации вдыхают жизнь в интерфейсы, обеспечивая визуальную обратную связь, направляя внимание пользователя и создавая запоминающиеся впечатления. Хорошо выполненная анимация ощущается естественной и интуитивной; плохо выполненная — вызывает задержки, отвлекает и даже может вызвать физический дискомфорт. Это руководство охватывает всё: от основ переходов и ключевых кадров до продвинутой оптимизации производительности и доступности, давая вам знания для создания плавных, целенаправленных и инклюзивных анимаций.
CSS-переходы и анимации
CSS предоставляет два различных механизма для создания движущихся эффектов: переходы и анимации. Понимание того, когда использовать каждый из них, является основой эффективной работы с CSS-анимацией.
CSS-переходы
Переходы анимируют изменение между двумя состояниями CSS-свойства. Вы определяете, какое свойство анимировать, продолжительность анимации и кривую плавности, а браузер автоматически обрабатывает интерполяцию между начальным и конечным значениями. Переходы запускаются изменениями состояния, такими как наведение, фокус, добавление класса или изменение свойства через JavaScript.
.button {
background: #3b82f6;
transform: scale(1);
transition: background 0.3s ease, transform 0.2s ease;
}
.button:hover {
background: #2563eb;
transform: scale(1.05);
}Переходы идеально подходят для простых двухсостоянийных анимаций. Они требуют минимума кода, легко понимаются и надёжно работают в браузерах. Ограничение в том, что они анимируют только между двумя значениями — нельзя определить промежуточные шаги.
CSS-анимации (ключевые кадры)
Анимации используют правило @keyframes для определения последовательности изменений стиля с произвольным количеством шагов. В отличие от переходов, анимации могут работать независимо от изменений состояния, бесконечно зацикливаться, воспроизводиться в обратном направлении и приостанавливаться. Они дают вам точный контроль над каждым кадром анимации.
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.8;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.pulse-element {
animation: pulse 2s ease-in-out infinite;
}Когда что использовать
| Сценарий | Использовать переходы | Использовать анимации |
|---|---|---|
| Эффекты наведения | Да | Нет |
| Состояния фокуса | Да | Нет |
| Переключение видимости | Да | Возможно |
| Многошаговые последовательности | Нет | Да |
| Циклические анимации | Нет | Да |
| Независимо от состояния | Нет | Да |
| Анимации появления | Возможно | Да |
Подробный разбор синтаксиса ключевых кадров
Правило @keyframes является ядром CSS-анимации. Полное понимание его синтаксиса раскрывает всю мощь многошаговых анимационных последовательностей.
Ключевые кадры на основе процентов
Ключевые кадры определяются с использованием процентных значений от 0% до 100%, представляющих прогресс на временной шкале анимации. Вы можете определить столько ключевых кадров, сколько необходимо, а браузер выполняет интерполяцию между ними:
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
25% {
transform: translateY(-20px);
}
50% {
transform: translateY(0);
}
75% {
transform: translateY(-10px);
}
}Несколько ключевых кадров могут совместно использовать один блок стилей, разделяя процентные значения запятыми, как в примере выше с 0%, 100%. Это полезно для анимаций, возвращающихся в начальное состояние.
Сокращённое свойство animation
Сокращённое свойство animation объединяет восемь подсвойств в одно объявление. Порядок: name, duration, timing-function, delay, iteration-count, direction, fill-mode и play-state.
.element {
animation: slideIn 0.5s ease-out 0.2s 1 forwards running;
}
/* Equivalent longhand */
.element {
animation-name: slideIn;
animation-duration: 0.5s;
animation-timing-function: ease-out;
animation-delay: 0.2s;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: forwards;
animation-play-state: running;
}Режимы заполнения анимации
Свойство animation-fill-mode управляет тем, какие стили применяются до и после выполнения анимации. Это одно из наиболее часто неправильно понимаемых свойств анимации:
- none (по умолчанию): элемент возвращается к стилям до анимации после её завершения.
- forwards: элемент сохраняет стили последнего кадра после завершения анимации. Критически важно для анимаций появления, где элемент должен оставаться в конечном положении.
- backwards: во время задержки анимации (до её начала) элемент применяет стили первого кадра.
- both: сочетает поведение forwards и backwards. Элемент показывает первый кадр во время задержки и сохраняет последний кадр после завершения.
Функции плавности
Функции плавности (также называемые функциями времени) определяют кривую ускорения анимации. Они определяют, начинается ли анимация медленно и затем ускоряется, начинается быстро и затем замедляется, или следует более сложному шаблону. Правильная функция плавности делает анимацию естественной; неправильная — механической или резкой.
Встроенные функции плавности
- linear: постоянная скорость на протяжении всей анимации. Редко выглядит естественно, поскольку объекты в реальном мире не движутся с постоянной скоростью. Подходит для механических или вращательных анимаций.
- ease (по умолчанию): начинается медленно, ускоряется в середине, замедляется в конце. Хорошая универсальная плавность для большинства UI-переходов.
- ease-in: начинается медленно, затем ускоряется. Создаёт ощущение «накопления импульса». Подходит для элементов, покидающих экран или падающих.
- ease-out: начинается быстро, затем замедляется. Создаёт ощущение «прибытия на место». Наиболее часто используемая плавность для элементов UI, входящих на экран.
- ease-in-out: медленное начало и конец, быстрее в середине. Похоже на ease, но с более выраженным ускорением и замедлением. Подходит для более крупных, драматичных переходов.
Кубические кривые Безье
Функция cubic-bezier() позволяет определить пользовательскую кривую плавности с точным контролем. Она принимает четыре параметра, представляющих контрольные точки кубической кривой Безье: cubic-bezier(x1, y1, x2, y2). Значения x представляют время (от 0 до 1), значения y — прогресс (могут выходить за пределы 0-1 для эффектов перехлёста).
.element {
/* Smooth deceleration - great for entrances */
transition: transform 0.3s cubic-bezier(0.0, 0.0, 0.2, 1.0);
/* Smooth acceleration - great for exits */
transition: transform 0.2s cubic-bezier(0.4, 0.0, 1, 1);
/* Material Design standard easing */
transition: transform 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
}Ступенчатые функции
Функция steps() создаёт дискретные покадровые анимации вместо плавной интерполяции. Это полезно для анимации спрайтов или создания эффекта «печати»:
@keyframes typing {
from { width: 0; }
to { width: 100%; }
}
.typing-effect {
animation: typing 3s steps(40, end);
overflow: hidden;
white-space: nowrap;
}Оптимизация производительности
Плавная анимация требует 60 кадров в секунду (fps), что означает, что каждый кадр должен быть завершён в течение 16,67 миллисекунд. Несоблюдение этого бюджета приводит к видимым задержкам — дрожанию, пропущенным кадрам и ухудшению пользовательского опыта. Понимание конвейера рендеринга браузера является ключом к написанию высокопроизводительных анимаций.
Конвейер рендеринга
При изменении CSS-свойства браузер проходит до трёх этапов для обновления отображения:
- Стилизация: определение того, какие CSS-правила применяются к каким элементам.
- Макет: вычисление размера и положения каждого элемента. Запускается изменениями width, height, margin, padding, top, left, font-size и других геометрических свойств.
- Отрисовка: заполнение пикселей для каждого элемента. Запускается изменениями color, background, box-shadow, border-radius и других визуальных свойств.
- Композиция: объединение отрисованных слоёв в правильном порядке. Только этот шаг выполняется на GPU. Запускается изменениями transform и opacity.
Анимации, запускающие только этап композиции, наиболее производительны, поскольку полностью пропускают макет и отрисовку. Вот почему transform и opacity являются золотым стандартом для высокопроизводительных CSS-анимаций.
Свойства только композиции
| Свойство | Запускает макет? | Запускает отрисовку? | GPU-композиция? |
|---|---|---|---|
| transform | Нет | Нет | Да |
| opacity | Нет | Нет | Да |
| filter | Нет | Да | Иногда |
| top / left | Да | Да | Нет |
| width / height | Да | Да | Нет |
| margin / padding | Да | Да | Нет |
| background-color | Нет | Да | Нет |
| box-shadow | Нет | Да | Нет |
Использование will-change
Свойство will-change сообщает браузеру, какие свойства ожидаемо изменятся, позволяя ему оптимизироваться заранее, продвигая элемент на собственный слой композитора. Однако его следует использовать с осторожностью:
/* Apply will-change just before the animation */
.element:hover {
will-change: transform;
}
/* Remove it after the animation completes */
.element {
transition: transform 0.3s ease;
}Распространённые ошибки will-change включают применение к слишком большому количеству элементов (каждый слой композитора потребляет память GPU) и постоянное удержание (трата ресурсов). Хорошая практика — добавлять will-change через JavaScript перед началом анимации и удалять после её завершения.
Использование Transform вместо свойств макета
Наиболее эффективная оптимизация производительности — замена свойств, запускающих макет, на transform:
- Используйте transform: translateX(100px) вместо left: 100px
- Используйте transform: translateY(50px) вместо top: 50px
- Используйте transform: scale(1.5) вместо width: 150%; height: 150%
- Используйте transform: rotate(45deg) вместо вращения через макет
Распространённые шаблоны анимации
Некоторые шаблоны анимации повторяются в веб-интерфейсах снова и снова. Освоение этих шаблонов даёт вам набор инструментов для большинства распространённых потребностей в UI-анимации.
1. Появление (fade-in)
Самая простая и универсальная анимация появления. Элемент переходит от прозрачного к непрозрачному:
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.4s ease-out forwards;
}2. Появление со сдвигом вверх
Более динамичный эффект появления, сочетающий вертикальное перемещение с изменением прозрачности. Это создаёт ощущение, что элемент прибывает снизу:
@keyframes slideUpFade {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.slide-up {
animation: slideUpFade 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}3. Масштабирование при наведении
Тонкое увеличение масштаба при наведении обеспечивает удовлетворительную интерактивную обратную связь:
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}4. Анимация списка с задержкой
Когда список элементов появляется, установка staggered задержки анимации для каждого элемента создаёт каскадный эффект, направляющий взгляд:
.list-item {
opacity: 0;
transform: translateY(10px);
animation: slideUpFade 0.3s ease-out forwards;
}
.list-item:nth-child(1) { animation-delay: 0.0s; }
.list-item:nth-child(2) { animation-delay: 0.05s; }
.list-item:nth-child(3) { animation-delay: 0.1s; }
.list-item:nth-child(4) { animation-delay: 0.15s; }
.list-item:nth-child(5) { animation-delay: 0.2s; }Для динамических списков используйте JavaScript для установки animation-delay на основе индекса каждого элемента или используйте CSS-пользовательские свойства: style="animation-delay: calc(var(--i) * 0.05s)".
5. Спиннер загрузки
Плавное непрерывное вращение — классический индикатор загрузки:
@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
width: 24px;
height: 24px;
border: 3px solid rgba(255, 255, 255, 0.2);
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}Доступность анимации: prefers-reduced-motion
Не все пользователи получают пользу от анимации. Для людей с вестибулярными расстройствами, чувствительностью к движению или определёнными когнитивными состояниями анимация может вызывать головокружение, тошноту или судороги. Медиа-запрос prefers-reduced-motion позволяет уважать системные настройки пользователя по уменьшению анимации.
Реализация уменьшенной анимации
Рекомендуемый подход — включать анимацию для пользователей, не установивших предпочтение уменьшения движения:
/* Default: no animation for users who prefer reduced motion */
.element {
opacity: 1;
transform: none;
}
/* Only animate for users who have no motion preference */
@media (prefers-reduced-motion: no-preference) {
.element {
animation: slideUpFade 0.5s ease-out forwards;
}
}В качестве альтернативы можно отключить определённые анимации для пользователей, предпочитающих уменьшенное движение:
.element {
animation: slideUpFade 0.5s ease-out forwards;
}
@media (prefers-reduced-motion: reduce) {
.element {
animation: none;
opacity: 1;
transform: none;
}
/* Keep functional transitions but shorten duration */
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}Что сохранить и что убрать
Когда пользователь предпочитает уменьшенную анимацию, не все анимации следует удалять. Функциональные анимации, передающие смысл или состояние, следует сохранить, но упростить:
- Удалить: декоративные анимации, параллакс-прокрутку, автопроигрываемые карусели, пульсирующие эффекты и циклические фоновые анимации.
- Упростить: длительность переходов должна быть сокращена до почти мгновенной (0,01 мс), а не полностью удалена, чтобы изменения состояния оставались заметными.
- Сохранить: функциональные переходы состояний (наведение, фокус, активное состояние), индикаторы прогресса и любые анимации, передающие важную информацию.
Библиотеки анимации
Хотя CSS-анимации обрабатывают большинство потребностей UI, библиотеки JavaScript-анимаций предоставляют продвинутые возможности, такие как анимация на основе физики, анимация, связанная с прокруткой, и оркестровка сложных последовательностей.
CSS-ориентированные библиотеки
- Animate.css: коллекция готовых классов CSS-анимации. Просто добавьте имя класса к элементу для применения анимации. Отлично подходит для быстрого прототипирования, но может привести к шаблонным эффектам при чрезмерном использовании.
- Hamburgers: коллекция анимированных переходов иконок гамбургер-меню, полностью реализованных на чистом CSS.
Библиотеки JavaScript-анимации
- Framer Motion: библиотека анимации React с декларативным API анимации, поддержкой пружинной физики, анимации макета и жестов. Лучший выбор для приложений React.
- GSAP (GreenSock): самая мощная библиотека JavaScript-анимации. Предоставляет точный контроль временной шкалы, сложную плавность, морфинг SVG и анимацию, запускаемую прокруткой. Используется крупными брендами для маркетинговых сайтов и интерактивных впечатлений.
- Anime.js: лёгкая библиотека JavaScript-анимации с лаконичным API. Поддерживает CSS-свойства, SVG, DOM-атрибуты и JavaScript-объекты. Хороший промежуточный вариант между CSS и GSAP.
- Motion One: современная лёгкая библиотека анимации, построенная на Web Animations API. Предоставляет минимальный API с поддержкой пружинной физики и временных шкал.
Когда использовать JavaScript против CSS
CSS для простых декларативных анимаций, реагирующих на изменения состояния. JavaScript для: анимации на основе физики (пружины, импульс), анимации, связанной с прокруткой, сложных последовательностей с точным временным контролем, динамических параметров анимации, вычисляемых во время выполнения, или анимаций, требующих программной паузы, реверса или перетаскивания.
Отладка анимации
Ошибки анимации могут быть трудноуловимыми и сложными для диагностики. Правильные инструменты и техники отладки делают процесс более эффективным.
Панель анимации Chrome DevTools
Chrome DevTools включает специализированную панель анимации с мощными возможностями отладки:
- Представление временной шкалы: просмотр всех активных анимаций на странице с их продолжительностью, задержками и ключевыми кадрами.
- Управление воспроизведением: замедление анимации до 1/4 скорости, пауза или перетаскивание временной шкалы по кадрам.
- Проверка свойств: щёлкните по анимации на временной шкале, чтобы увидеть точные CSS-свойства, которые анимируются, и их значения на каждом ключевом кадре.
- Редактирование в реальном времени: изменяйте продолжительность, задержки и плавность анимации в реальном времени без перезагрузки страницы.
Анализ производительности
Используйте панель Performance в Chrome DevTools для выявления проблем с производительностью анимации:
- Запись трассировки производительности во время выполнения анимации
- Поиск кадров, превышающих бюджет в 16,67 мс (отображаются красными полосами на графике кадров)
- Проверка наличия операций «Layout» в кадрах анимации, что указывает на свойства, запускающие макет
- Использование вкладки «Rendering» для включения «Paint flashing» (показывает области перерисовки зелёным) и «Layer borders» (показывает слои композитора)
Распространённые сценарии отладки
- Анимация не работает: проверьте, правильно ли установлен animation-fill-mode. Без forwards или both элемент возвращается в состояние до анимации. Также убедитесь, что элемент имеет правильные размеры — transform: scale(0) делает элемент невидимым, но он всё ещё существует.
- Анимация дёргается: откройте панель Performance и ищите длинные кадры. Проверьте, не анимируете ли вы свойства, запускающие макет. Переключитесь на transform и opacity.
- Задержка анимации ощущается неправильно: помните, что animation-delay создаёт промежуток перед началом анимации. В течение этого промежутка элемент показывает состояние до анимации, если не установлен animation-fill-mode: backwards или both.
- Анимация работает в Chrome, но не в Safari: Safari более строг в разборе сокращения animation. Убедитесь, что все значения в правильном порядке и не используются неподдерживаемые функции.
Работаете с CSS? Попробуйте наши бесплатные инструменты CSS для форматирования, минификации и оптимизации ваших таблиц стилей для production.
CSS-форматтерCSS-минификаторЧасто задаваемые вопросы
Следует ли использовать CSS-переходы или CSS-анимации?
CSS-переходы используются для простых изменений состояния из точки A в точку B, таких как эффекты наведения, состояния фокуса и переключение видимости. CSS-анимации (ключевые кадры) используются для сложных многошаговых последовательностей, циклических анимаций или анимаций, которые должны работать независимо от изменений состояния. Переходы проще; анимации предоставляют больше контроля.
Какие CSS-свойства безопасно анимировать для производительности?
Наиболее производительными свойствами для анимации являются transform и opacity, поскольку они могут полностью обрабатываться композитором GPU без запуска макета или отрисовки. Другие свойства, такие как width, height, margin и top, запускают пересчёт макета, что дорого. Всегда предпочитайте transform: translateX() вместо left и transform: scale() вместо изменений width/height.
Как обеспечить доступность для пользователей, чувствительных к анимации?
Используйте медиа-запрос prefers-reduced-motion для отключения или упрощения анимации для пользователей, включивших настройку «уменьшить движение» в операционной системе. Оборачивайте несущественные анимации в @media (prefers-reduced-motion: no-preference) и предоставляйте мгновенные изменения состояния в качестве запасного варианта для пользователей, предпочитающих уменьшенную анимацию.
Что такое will-change и когда его следует использовать?
will-change — это CSS-свойство, которое подсказывает браузеру, какие свойства изменятся в будущем, позволяя ему оптимизироваться заранее. Используйте экономно и только при наблюдении проблем с производительностью. Применяйте перед началом анимации и удаляйте после её завершения. Чрезмерное использование will-change тратит память GPU и может фактически ухудшить производительность.
Как отлаживать CSS-анимации?
Chrome DevTools предоставляет мощные инструменты отладки анимации. Откройте панель Animations (в меню More Tools), чтобы увидеть все активные анимации, перетаскивать временную шкалу, изменять продолжительность и задержки в реальном времени и замедлять анимацию до 1/4 скорости. Вы также можете использовать панель Performance для выявления проблем с производительностью анимации и дрожания макета.