
CSS-анимации: примеры, готовый код и современные возможности
ДБ
Дмитрий Борисенко
Анимация в CSS собирается из двух вещей: описания кадров и подключения их к элементу. На этом теория заканчивается — дальше начинаются детали, из-за которых движение либо оживляет интерфейс, либо раздражает и дёргается.
Разберём, как сделать анимацию, чем animation отличается от transition,
почему движение тормозит и что появилось в CSS за последние пару лет. Появилось
многое, и часть привычных приёмов больше не нужна.
Как сделать анимацию в CSS
Сначала описываете кадры в правиле @keyframes: что происходит в начале и в
конце. Потом подключаете их свойством animation — имя и длительность
обязательны, остальное по необходимости.
Кадров может быть сколько угодно — вместо from и to пишите проценты: 0%,
50%, 100%.
Ключевое слово both в конце — это animation-fill-mode. Без него элемент
мигнёт: до старта анимации он покажется в исходном состоянии, а после — вернётся
к нему. both удерживает первый и последний кадр.
Собрать свои кадры ползунками и сразу увидеть результат:
CSS-анимации: примеры и готовый код
Соберите анимацию на @keyframes или возьмите готовую: появление, пульсация, загрузка, анимация кнопки при наведении.
Попробовать
animation или transition
Разница в том, кто запускает движение.
Transition реагирует на событие — наведение, клик, добавление класса — и умеет переходить только между двумя состояниями.
Animation живёт сама: стартует без событий, проходит через любое число кадров и может повторяться бесконечно.
Правило простое: наведение и клик — transition; лоадер, пульсация, появление
при загрузке страницы — animation.
Готовые анимации для копирования
Появление элемента
Самая частая анимация: блок всплывает снизу и проявляется.
Пульсация
Мягко привлекает внимание к кнопке или индикатору. Работает бесконечно, поэтому не ставьте её на важный текст — читать под пульсацией невозможно.
Спиннер загрузки
Линейная функция времени здесь обязательна: любая другая даст рывок на стыке оборотов.
Мерцание скелетона
Заглушка на месте ещё не загруженного контента. Двигаем градиент, а не размеры, поэтому вёрстка не пересчитывается.
Встряска при ошибке
Короткое движение по горизонтали — понятный сигнал о неверном пароле.
Каскад: элементы появляются по очереди
Задержку удобно вынести в переменную и задать прямо в разметке. Но есть
тонкость: чтобы переменная работала в calc(), её нужно зарегистрировать —
иначе браузер не знает, что там число, и задержка схлопнется в ноль.
Почему анимация дёргается
Почти всегда причина одна: анимируются свойства, которые меняют вёрстку.
width, height, margin, top, left заставляют браузер пересчитывать
раскладку всей страницы на каждом кадре. А transform и opacity считаются
на видеокарте и вёрстку не трогают вовсе.
То же с увеличением: scale() вместо изменения width и height.
will-change: не оставляйте его в CSS
Это свойство часто советуют «для оптимизации» и прописывают навсегда. Так делать не надо: оно держит элемент на отдельном слое постоянно, съедая память видеокарты. На странице с сотней таких элементов лечение окажется хуже болезни.
Включайте его только тогда, когда анимация вот-вот начнётся.
Старый хак transform: translateZ(0) для той же цели давно не нужен — это
карго-культ из 2014 года.
Доступность: это не «хорошая практика»
Часть людей отключает анимации в настройках системы — из-за укачивания, мигреней, вестибулярных нарушений. Для них движущийся интерфейс не «живой», а физически неприятный.
Уважить эту настройку — требование доступности, а не пожелание.
Более честный подход — не выключать анимацию, а включать её только тем, кто не против:
Разница принципиальная. В первом случае вы анимируете всех и потом «глушите», во втором движения по умолчанию нет вовсе. Второй вариант особенно важен для бесконечных анимаций вроде пульсации: именно на них жалуются чаще всего.
Плавность: функции времени
Кривая скорости решает, ощущается движение живым или механическим.
linear— постоянная скорость. Годится только для вращения.ease-out— быстрый старт, мягкое торможение. Лучший выбор для интерфейса: элемент влетает и плавно останавливается.ease-in— наоборот, для исчезновения.ease-in-out— разгон и торможение, для движения «туда-обратно».
Если стандартных не хватает, задайте свою кривую четырьмя числами. Подбирать их вслепую мучительно — тяните контрольные точки мышью:
Cubic-bezier: кривая плавности для CSS
Потяните за контрольные точки и получите свою cubic-bezier() для transition-timing-function или animation-timing-function.
Попробовать
linear(): пружины и отскоки
cubic-bezier умеет только одну плавную дугу — настоящий отскок им не описать.
Для этого есть функция linear(): она задаёт кривую по точкам, и через неё
выражаются пружины, отскоки и затухающие колебания.
Выглядит пугающе, но такие кривые генерируют, а не пишут руками.
Что появилось в CSS недавно
Часть приёмов, ради которых годами тащили JavaScript, теперь делается на CSS.
@starting-style: появление из display: none
Классическая боль: элемент нельзя плавно показать, если он был display: none —
анимировать не от чего, состояния просто не существовало. Теперь стартовое
состояние можно задать явно.
Работает для модалок, поповеров и <dialog> — всего, что появляется из небытия.
@property: анимация переменных и градиентов
Обычную CSS-переменную нельзя анимировать. Браузер видит в ней просто набор символов, а не цвет или угол, поэтому не может посчитать промежуточные значения — и переключает её скачком в середине перехода.
@property сообщает браузеру тип. После регистрации переменная становится
анимируемой, и открывается то, что раньше требовало JavaScript: плавное вращение
градиента, анимация угла, счётчики.
Подробнее про переменные — в статье про CSS custom properties.
Анимации по скроллу без JavaScript
Раньше «появление при прокрутке» делали через IntersectionObserver. Теперь
анимацию можно привязать к позиции скролла прямо в CSS.
Оговорка: в Firefox это пока за флагом, поэтому подключайте как улучшение. Без поддержки элемент просто останется видимым — ничего не сломается.
Сколько должна длиться анимация
Цифры, которые экономят время на подборе:
- 100–200 мс — реакция на действие: наведение, нажатие. Быстрее человек не заметит, медленнее — почувствует лаг.
- 200–500 мс — появление элементов, раскрытие панелей.
- 500–1000 мс — крупные переходы, смена экранов.
Всё, что дольше секунды, воспринимается как тормоза, даже если выглядит красиво.
Отладка
В DevTools есть панель Animations: она ловит все запущенные анимации, даёт
поставить их на паузу, промотать по кадрам, замедлить и прямо на месте
подправить кривую. Это на порядок удобнее, чем ставить animation-duration: 10s
и смотреть в замедлении.
Отдельно стоит проверить, как движение сказывается на скорости страницы: тяжёлые анимации — частая причина просевших метрик, и складываются они не так, как многие думают. Об этом — в статье про оценку Lighthouse.
Коротко
transition— на событие,animation— сама по себе.- Анимируйте
transformиopacity. Всё остальное заставляет браузер пересчитывать вёрстку на каждом кадре. will-changeвключают перед анимацией и снимают после, а не держат в CSS постоянно.prefers-reduced-motion— обязателен, а не желателен.- Переменную нельзя анимировать без
@property. - Появление из
display: noneтеперь делается на CSS через@starting-style.



