В наших веб-проектах мы часто используем CSS-анимации — они позволяют без JavaScript придавать элементам страницы интерактивность. Сегодня разберём, по какому принципу работают анимации в CSS, какие есть основные свойства и где брать интересные элементы для своих проектов.
Введение в CSS-анимации
Анимации в веб-дизайне — это не просто эффектный элемент, на самом деле они выполняют важные задачи. С их помощью можно привлечь внимание пользователей к ключевым деталям интерфейса и улучшить пользовательский опыт.
Анимации делают интерфейс более понятным, показывая, что происходит: загрузка данных, переход между страницами или результат действия. К тому же аккуратные и плавные движения создают ощущение продуманного и современного дизайна. Интерфейс становится не только визуально приятным, но и функциональным.
В CSS анимации реализуются без использования JavaScript и работают благодаря двум возможностям:
- Правило
@keyframes
, которое определяет ключевые кадры анимации и задаёт, как элемент будет двигаться или изменяться. - Свойство
animation
, которое применяется к элементу и отвечает за управление анимацией — её продолжительность, задержку, направление и другие параметры.
Получается, что сначала мы описываем набор правил для анимации, а затем подключаем её к элементу. В комбинации эти возможности позволяют создавать сложные эффекты — от простого мигания текста до имитации физических движений.
Теперь подробно рассмотрим, как это работает.
Правило @keyframes
CSS-анимации строятся на основе правила @keyframes
, которое позволяет задать ключевые кадры (состояния) анимации. С помощью @keyframes
мы описываем, как изменяется внешний вид элемента на протяжении всей анимации.
Но сам по себе @keyframes
— это просто набор инструкций. Чтобы анимация начала работать, её нужно подключить к элементу с помощью свойства animation
. Оно связывает элемент с конкретной анимацией, задаёт её продолжительность, задержку, направление и другие параметры.
Синтаксис @keyframes
простой:
@keyframes имя_анимации {
from { /* начальное состояние */ }
to { /* конечное состояние */ }
}
Если нужно больше контроля, можно задавать промежуточные состояния в процентах:
@keyframes имя_анимации {
0% { /* начальное состояние */ }
50% { /* состояние в середине */ }
100% { /* конечное состояние */ }
}
Суть анимации — в постепенном переходе от одного набора CSS-стилей к другому. В процессе анимации можно изменять набор стилей несколько раз, задавая промежуточные состояния для создания сложных и динамичных эффектов. Мы можем анимировать следующие CSS-свойства:
- Позиционирование —
transform
,top
,left
,right
,bottom
. - Цвета —
color
,background-color
,border-color
. - Размеры —
width
,height
,padding
,margin
. - Прозрачность —
opacity
. - Тени —
box-shadow
,text-shadow
. - Контуры —
border-width
,border-radius
.
Примеры использования @keyframes
Правило @keyframes
используют для создания различных эффектов — движения, затемнения, вращения и так далее. Рассмотрим пару примеров:
/* Изменение прозрачности элемента */
@keyframes fadeIn {
from {
opacity: 0; /* Начальная прозрачность */
}
to {
opacity: 1; /* Полностью видимый */
}
}
/* Изменение цвета элемента */
@keyframes colorChange {
0% {
/* Красный цвет */
background-color: red;
}
50% {
/* Жёлтый цвет */
background-color: yellow;
}
100% {
/* Зелёный цвет */
background-color: green;
}
}
Дальше, чтобы эти анимации заработали, их нужно подключить к элементу через свойство animation
.
Свойство animation
Свойство animation
отвечает за то, как анимации применяются к элементу. С его помощью можно задать, что именно будет происходить, сколько это займёт времени, как часто станет повторяться и с какой скоростью. Анимацию можно настроить с помощью отдельных свойств или указать всё сразу в сокращённой форме.
animation-name
Это имя нашей анимации, которая прописана в @keyframes
. Без него ничего работать не будет — именно так CSS понимает, какую анимацию нужно запустить.
/* Определяем анимацию затухания */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.element {
/* Применяем анимацию через animation-name */
animation-name: fadeIn;
/* Указываем длительность, чтобы анимация заработала */
animation-duration: 2s;
}
animation-duration
Свойство animation-duration
задаёт, сколько времени займёт выполнение одного цикла анимации. Значение указывается в секундах (s) или миллисекундах (ms). Например:
/* анимация выполняется за 2 секунды */
animation-duration: 2s;
Если animation-duration
не задано, анимация не будет видна, так как её выполнение займёт 0 секунд.
animation-timing-function
Свойство animation-timing-function
определяет кривую скорости анимации, то есть то, как она изменяет CSS-стили в течение времени. Кривая скорости задаёт, сколько времени потребуется для перехода от одного набора стилей к другому на каждом этапе анимации. Свойство помогает сделать переходы более плавными и естественными, избегая резких изменений.
Например:
- С
ease-in
анимация начинается медленно, затем ускоряется. - С
ease-out
анимация быстро стартует и замедляется к концу.
Все эти значения основаны на кривых Безье (Cubic Bezier). Это математический способ описания кривой скорости анимации. Есть даже интерактивный сайт, где можно настраивать кривую Безье, изменяя точки на графике, и сразу видеть, как изменяется анимация.
animation-iteration-count
Свойство animation-iteration-count
определяет, сколько раз должна воспроизводиться анимация. Значением у animation-iteration-count
может быть либо число, либо infinite
:
- число указывает точное количество повторений;
infinite
задаёт бесконечное воспроизведение анимации.
.element {
/* Анимация выполнится два раза */
animation-iteration-count: 2;
}
.element {
/* Анимация будет повторяться бесконечно */
animation-iteration-count: infinite;
}
animation-direction
Свойство animation-direction
задаёт направление воспроизведения анимации: вперёд, назад или чередуя направления. Возможных значений у свойства может быть много:
animation-direction: normal|reverse|alternate|alternate-reverse|initial|inherit;
Разберёмся на примере. Допустим, у нас есть анимация перемещения прямоугольника div
. Он горизонтально сдвигается на 100 пикселей:
@keyframes slide {
from {
/* Начальная позиция */
transform: translateX(0);
}
to {
/* Конечная позиция */
transform: translateX(100px);
}
}
С помощью animation-direction
мы можем задать разные направления движения для разных прямоугольников:
/* анимация движется только вперёд (от начального кадра к конечному) */
.normal {
/* Синий цвет */
background-color: #3498db;
/* Имя анимации */
animation-name: slide;
/* Длительность одного цикла — 2 секунды */
animation-duration: 2s;
/* Анимация повторяется бесконечно */
animation-iteration-count: infinite;
/* Движение только вперёд */
animation-direction: normal;
}
/* анимация движется в обратном направлении (от конечного кадра к начальному) */
.reverse {
/* Красный цвет */
background-color: #e74c3c;
animation-name: slide;
animation-duration: 2s;
animation-iteration-count: infinite;
/* Движение назад */
animation-direction: reverse;
}
/* направление чередуется (сначала вперёд, затем назад) */
.alternate {
/* Зелёный цвет */
background-color: #2ecc71;
animation-name: slide;
animation-duration: 2s;
animation-iteration-count: infinite;
/* Сначала вперёд, затем назад */
animation-direction: alternate;
}
/* направление чередуется, начиная с обратного (сначала назад, затем вперёд) */
.alternate-reverse {
/* Жёлтый цвет */
background-color: #f1c40f;
animation-name: slide;
animation-duration: 2s;
animation-iteration-count: infinite;
/* Сначала назад, затем вперёд */
animation-direction: alternate-reverse;
}
На странице это будет выглядеть так:
Если мы пропишем значение initial
, то будет установлено значение по умолчанию (normal
).
Значение inherit
наследует значение от родительского элемента.
animation-delay
Свойство animation-delay
задаёт задержку перед началом анимации. Мы можем явно указать, через какое время после применения стилей анимация начнёт воспроизводиться. Значение указывается в секундах или миллисекундах.
.element {
/* Задержка перед началом анимации — 2 секунды */
animation-delay: 2s;
}
animation-play-state
Свойство animation-play-state
определяет, находится ли анимация в состоянии воспроизведения или паузы. Это позволяет управлять анимацией, останавливая её в нужный момент или возобновляя выполнение. Это особенно полезно при использовании JavaScript, чтобы останавливать или запускать анимацию динамически, например по событию нажатия кнопки или наведению мыши.
Когда анимация находится на паузе, она «запоминает» текущую позицию и продолжает воспроизведение с того же момента после снятия паузы.
Можно прописать одно из двух значений:
running
— воспроизводится (по умолчанию);paused
— приостанавливается, в этом состоянии элемент остаётся в текущем кадре анимации.
Допустим, на странице есть кнопка, которая движется из стороны в сторону. Мы хотим сделать так, чтобы при наведении курсора мыши на эту кнопку движение прекращалось. Для этого пропишем саму анимацию движения:
@keyframes move {
from {
transform: translateX(0);
}
to {
transform: translateX(200px);
}
}
Теперь применим её к кнопке и зададим animation-play-state — running
. То есть при загрузке страницы анимация срабатывает:
button {
/* остальные стили кнопки опущены для краткости */
/* Имя анимации */
animation-name: move;
/* Длительность анимации */
animation-duration: 3s;
/* Бесконечное повторение */
animation-iteration-count: infinite;
/* Анимация воспроизводится по умолчанию */
animation-play-state: running;
}
Анимация работает, кнопка по умолчанию движется, но при наведении курсора пока ничего не происходит:
Теперь зададим кнопке псевдокласс hover и пропишем в нём остановку анимации:
/* При наведении ставим анимацию на паузу */
button:hover {
/* Анимация приостанавливается */
animation-play-state: paused;
}
Теперь при наведении курсора движение кнопки останавливается:
А если нужно сделать что-то ещё более сложное, например останавливать анимации на определённом этапе, возобновлять анимацию по таймеру или по другим условиям, то здесь в дополнение уже понадобится JavaScript.
animation-fill-mode
Свойство animation-fill-mode
определяет, как элемент выглядит до начала анимации и после её завершения. Обычно анимация влияет на элемент только во время своего выполнения: до старта он выглядит как обычно, а после окончания возвращается в исходное состояние. Но с помощью animation-fill-mode
можно изменить это поведение, чтобы элемент запоминал своё начальное или конечное состояние. Например, можно сделать так, чтобы он сразу выглядел, как в начале анимации, или сохранял стиль после её завершения.
У этого свойства есть четыре параметра:
None
(значение по умолчанию). Анимация влияет на элемент только во время своего выполнения. До начала и после завершения анимации элемент возвращается к своим исходным стилям.Forwards
. После завершения анимации элемент остаётся в том состоянии, которое задано в последнем ключевом кадре.Backwards
. До начала анимации, включая время задержки, элемент принимает стили из первого ключевого кадра. Это нужно, чтобы избежать резких изменений, пока анимация ещё не началась.Both
. Элемент сразу принимает стили первого ключевого кадра до начала анимации и сохраняет стили последнего кадра после её завершения. Это объединяет поведение значенийforwards
иbackwards
.
Посмотрим на примере. Допустим, у нас есть анимированный блок, который меняется в размерах и цветах — из синего становится зелёным. Мы хотим, чтобы по завершении анимации он оставался в последнем трансформированном состоянии:
Задаем ключевые кадры анимации:
@keyframes resizeAndColor {
0% {
/* Начальная ширина */
width: 100px;
/* Начальная высота */
height: 100px;
/* Начальный цвет */
background-color: #683eef;
}
100% {
/* Конечная ширина */
width: 200px;
/* Конечная высота */
height: 200px;
/* Конечный цвет */
background-color: #d6fb51;
}
}
Теперь прописываем стили для нашего блока и подключаем к нему анимацию:
.block {
/* Начальная ширина */
width: 100px;
/* Начальная высота */
height: 100px;
/* Начальный цвет */
background-color: #683eef;
/* Имя анимации */
animation-name: resizeAndColor;
/* Длительность анимации */
animation-duration: 3s;
/* Сохраняем конечное состояние */
animation-fill-mode: forwards;
}
Вот что получилось:
Блок при загрузке страницы меняет цвет, увеличивается и остаётся в новом состоянии по завершении анимации. А если мы пропишем вместо forwards
значение backwards
, то блок возвратится в состояние первого ключевого кадра, то есть станет маленьким и синим.
Краткая запись анимации
Значения в свойстве animation
можно объединить в одну строку: имя, длительность, тайминг-функцию, задержку, количество повторений, направление, поведение до и после выполнения. В краткой записи свойства animation
можно указать все значения, но в определённом порядке. Если мы не указываем какое-то значение, используется его значение по умолчанию:
/* @keyframes duration | easing-function | delay | iteration-count | direction | fill-mode | play-state | name */
animation: 3s ease-in 1s 2 reverse both paused slide-in;
В этой записи мы прописали длительность анимации, тайминг-функцию, задержку, количество повторений, направление, режим заполнения, состояние воспроизведения и имя анимации.
Применение нескольких анимаций
Можно назначить одному элементу сразу несколько анимаций, указав их через запятую в свойстве animation
. Это позволяет комбинировать эффекты с разными таймингами, длительностью, направлениями и так далее.
Сделаем красивую вращающуюся анимацию. Возьмём элемент и заставим его плавно вращаться сначала в одну сторону, потом в другую, а затем добавить бесконечное чередование движений. Мы используем несколько ключевых кадров и объединим их в одну сложную анимацию.
Сначала сделаем базовую HTML-разметку и добавим элемент, который хотим анимировать:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Анимация</title>
<!-- Подключаем файл стилей -->
<link rel="stylesheet" href="animation.css">
</head>
<body>
<!-- Элемент, который будет вращаться -->
<img src="https://thecode.media/wp-content/themes/thecode_refresh/assets/svg/logo.svg" class="element"></img>
</body>
</html>
Теперь в файле со стилями пропишем стили для элемента:
/* Стили для элемента */
.element {
/* Задаём ширину элемента */
width: 136px;
}
Пока что у нас получился просто логотип на белом фоне:
Начнём анимировать его. Зададим для него три отдельные анимации (spin1, spin2, spin3). Каждая из них отвечает за свой этап движения:
- spin1 — вращение элемента на 180°;
- spin2 — продолжение вращения до 360°;
- spin3 — вращение на 360° в обратную сторону с чередованием.
/* Первая анимация: вращение на 180° */
@keyframes spin1 {
from {
/* Начальная позиция */
transform: rotate(0deg);
}
to {
/* Вращение на 180° */
transform: rotate(180deg);
}
}
/* Вторая анимация: вращение на оставшиеся 180° */
@keyframes spin2 {
from {
/* Продолжение со 180° */
transform: rotate(180deg);
}
to {
/* Завершение полного круга */
transform: rotate(360deg);
}
}
/* Третья анимация: вращение в обратную сторону */
@keyframes spin3 {
from {
/* Начальная позиция */
transform: rotate(0deg);
}
to {
/* Вращение на 360° в противоположную сторону */
transform: rotate(-360deg);
}
}
Мы прописали правила для трёх анимаций, но пока ничего не происходит — сами анимации ещё не подключены к элементу. Для этого мы используем свойство animation
, которое связывает элемент с нашими анимациями.
Также в этом свойстве мы указываем скорость выполнения каждой анимации (время), тайминг-функцию и дополнительные параметры — задержку (delay
) и бесконечное повторение (infinite
).
Добавим всё это к элементу, чтобы анимации начали работать:
.element {
width: 136px;
/* Подключение трёх анимаций */
animation:
spin1 1s linear, /* Первая анимация: вращение на 180° за 1 секунду с линейной скоростью */
spin2 2s ease 1.5s, /* Вторая анимация: вращение до 360° за 2 секунды, начинается с задержкой 1,5 секунды */
spin3 5s ease-in-out 4s infinite alternate; /* Третья анимация: вращение в обратную сторону на 360° с чередованием, бесконечно */
}
Смотрим, что получилось:
Примеры CSS-анимаций
Для создания движения часто используют свойство transform
, которое поддерживает функции translate
, rotate
, scale
и их комбинации. Это позволяет создавать разные красивые штуки: вращающиеся спиннеры, пульсирующие индикаторы и сложные переходы между формами.
Пример анимации с дополнительным JS:
В веб-проекте «Делаем аквариум с разными обитателями» мы использовали анимацию для движения рыбок. С помощью свойства transform
рыбки плывут из одной стороны аквариума в другую, затем разворачиваются, используя scaleX
, и возвращаются обратно.
https://thecode.media/wp-content/uploads/2024/01/aquarium-1.gif
В веб-проекте «Делаем браузерную игру с динозавриком, как в Chrome», мы реализовали прыжки динозаврика с помощью свойства top
. Каждый ключевой кадр определял положение динозаврика на определённой стадии прыжка: от начальной позиции до самой высокой точки и обратно.
https://thecode.media/wp-content/uploads/2024/05/unnamed.gif
Доступность анимаций
Не все пользователи любят или могут воспринимать активные анимации. Например, кому-то комфортно смотреть на сложные движения или мерцания на экране. Некоторые анимации даже могут вызывать дискомфорт или ухудшать восприятие контента. Поэтому важно делать их доступными для всех.
Благодаря медиазапросу prefers-reduced-motion
можно уменьшить или отключить анимации для тех, кто предпочитает минимальное движение.
Современные браузеры поддерживают настройку prefers-reduced-motion
. Это системный параметр, который пользователи включают, чтобы уменьшить или отключить анимации. С помощью этого медиазапроса можно адаптировать сайт:
/* Убираем анимацию для пользователей с prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
.element {
/* Отключаем анимацию */
animation: none;
}
}
Если пользователь включил настройку «уменьшить движения» (Reduce Motion) в своей системе, анимация автоматически отключится. Это простой способ позаботиться о пользователе и сделать UX сайта лучше.
Кроме того, вспышки и быстро меняющиеся кадры могут вызвать дискомфорт у пользователей с повышенной чувствительностью. Поэтому важно использовать плавные переходы — ease-in-out
и прочие.
Поддержка браузерами
Современные браузеры хорошо поддерживают большинство возможностей CSS-анимаций — @keyframes
, сокращённую запись animation
и медиазапросы prefers-reduced-motion
.
В старых версиях Internet Explorer (до IE 11) и некоторых устаревших браузерах поддержка анимаций отсутствует или ограничена. Если важна обратная совместимость, используйте полифилы, то есть дополнительные библиотеки или скрипты, которые добавляют поддержку функциональности CSS-анимаций в браузерах.
Dev Tools в браузерах позволяют эмулировать настройки, например prefers-reduced-motion
, и тестировать поведение анимаций во вкладке «Анимации».
Полезные ресурсы и библиотеки
Чтобы упростить создание анимаций и вдохновиться интересными эффектами, можно использовать готовые ресурсы и инструменты — библиотеки и генераторы для анимаций:
- Animista — интерактивный генератор анимаций с большим выбором эффектов. Выберите нужный эффект, настройте параметры и получите готовый CSS-код.
- Keyframes — инструмент для создания и настройки анимаций прямо в браузере. Позволяет визуально редактировать ключевые кадры.
- Animate.css — популярная библиотека с готовыми эффектами. Подключите её и добавьте классы для быстрого использования анимаций.
- Hover.css — коллекция эффектов наведения для кнопок, ссылок и других элементов.
- GSAP (GreenSock) — инструмент для сложных и кроссбраузерных анимаций. Работает с CSS, SVG и JavaScript.