CSS-анимации: примеры и готовый код

Соберите анимацию на @keyframes или возьмите готовую: появление, пульсация, загрузка, анимация кнопки при наведении.

DEMO
Кадры
CSS
@keyframes myAnimation {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.2);
  }
  100% {
    transform: scale(1);
  }
}

.animated-element {
  animation-name: myAnimation;
  animation-duration: 1s;
  animation-timing-function: ease;
  animation-iteration-count: 1;
}

/* Сокращенная запись */
.animated-element {
  animation: myAnimation 1s ease 1;
}

Готовые анимации — кликните, чтобы загрузить в конструктор

Как сделать анимацию в CSS

Анимация собирается из двух частей. Сначала вы описываете кадры в правиле @keyframes: что происходит в начале и в конце. Потом подключаете их к элементу свойством animation. Имя и длительность обязательны, остальное по необходимости.

css
/* 1. описываем кадры */
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* 2. подключаем к элементу */
.card {
  animation: fadeIn 0.5s ease both;
}

Кадров может быть сколько угодно. Вместо from и to пишите проценты: 0%, 50%, 100%. Конструктор выше собирает такой код визуально: вы двигаете ползунки, а он отдаёт готовое правило.

Готовые CSS-анимации

Пять анимаций, которые закрывают почти все задачи интерфейса. Демо слева крутятся бесконечно, чтобы их было видно. В коде повтор стоит только там, где он нужен по смыслу.

Появление элемента

Самая частая анимация. Блок всплывает снизу и проявляется. fill-mode: both удерживает конечное состояние, иначе элемент мигнёт обратно.

css
@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

.card {
  animation: fadeInUp 0.5s ease both;
}

Пульсация

Мягко привлекает внимание к кнопке или индикатору. Работает бесконечно, поэтому не ставьте её на важный текст.

css
@keyframes pulse {
  0%, 100% { transform: scale(1);    opacity: 1;   }
  50%      { transform: scale(1.08); opacity: 0.8; }
}

.badge {
  animation: pulse 1.5s ease-in-out infinite;
}

Загрузка, спиннер

Бесконечное вращение с линейной функцией времени. Любая другая даст рывок на стыке оборотов.

css
@keyframes spin {
  to { transform: rotate(360deg); }
}

.loader {
  animation: spin 0.8s linear infinite;
}

Мерцание, скелетон

Заглушка на месте ещё не загруженного контента. Двигаем градиент, а не размеры, поэтому вёрстка не пересчитывается.

css
@keyframes shimmer {
  from { background-position: -200% 0; }
  to   { background-position:  200% 0; }
}

.skeleton {
  background: linear-gradient(
    90deg,
    #e5e7eb 25%, #f3f4f6 50%, #e5e7eb 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.4s linear infinite;
}

Встряска при ошибке

Короткое движение по горизонтали, понятный сигнал о неверном пароле или незаполненном поле.

css
@keyframes shake {
  0%, 100%      { transform: translateX(0);    }
  20%, 60%      { transform: translateX(-6px); }
  40%, 80%      { transform: translateX(6px);  }
}

.input.error {
  animation: shake 0.4s ease;
}

Анимация кнопки при наведении

Для наведения @keyframes обычно не нужен, хватает transition. Она оживляет переход между обычным состоянием и :hover, и это дешевле. Наведите курсор на карточку ниже.

Наведите на меня
css
.card {
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

Тень для такой карточки удобно подобрать в генераторе теней.

animation или transition

Разница в том, кто запускает движение. Transition реагирует на событие: наведение, клик, добавление класса. Переходить он умеет только между двумя состояниями. Animation живёт сама, стартует без событий, проходит через любое число кадров и может повторяться бесконечно. Наведение и клик — transition; лоадер, пульсация, появление при загрузке страницы — animation.

Свойства анимации

СвойствоЧто делает
animation-nameИмя правила @keyframes, которое нужно проиграть.
animation-durationДлительность одного цикла. Для интерфейса обычно 0.2–0.6s, дольше движение начинает раздражать.
animation-timing-functionКривая скорости. Бывает ease, linear, ease-in-out или своя cubic-bezier().
animation-delayЗадержка перед стартом. Разные задержки у соседних элементов дают эффект каскада.
animation-iteration-countЧисло повторов. Значение infinite крутит анимацию бесконечно.
animation-directionНаправление. Значение alternate проигрывает каждый второй цикл задом наперёд, движение идёт туда-обратно без рывка.
animation-fill-modeЧто показывать до и после анимации. Значение both оставляет элемент в конечном кадре.

Всё это записывается одной строкой: animation: pulse 1.5s ease-in-out 0s infinite alternate both. Свою кривую скорости можно собрать в генераторе cubic-bezier.

Почему анимация дёргается

Почти всегда причина одна: анимируются свойства, которые меняют вёрстку. width, height, margin, top и left заставляют браузер пересчитывать раскладку страницы на каждом кадре. А transform и opacity считаются на видеокарте и вёрстку не трогают. Поэтому сдвиг делайте через transform: translate(), а увеличение через transform: scale(), а не изменением размеров.

И не забудьте про тех, кому движение мешает физически. Часть людей отключает анимации в настройках системы. Уважить эту настройку можно одним медиазапросом.

css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

Больше приёмов и разбор нетривиальных случаев собраны в подробном гайде по CSS-анимациям.

Похожие инструменты

Другие полезные инструменты из той же категории

Часто задаваемые вопросы

Нужны две вещи. Сначала описываете кадры в правиле @keyframes: что происходит в начале (0% или from) и в конце (100% или to). Затем подключаете их к элементу свойством animation, указав имя и длительность: animation: fadeIn 0.5s ease. Всё остальное — задержку, повторы, направление — добавляете при необходимости. Конструктор выше собирает такой код сам.

Transition оживляет переход между двумя состояниями и запускается только по событию — например, при наведении. Animation умеет больше: она проигрывается сама, может иметь сколько угодно промежуточных кадров и повторяться бесконечно. Правило простое: наведение и клик — transition, самостоятельное движение вроде лоадера или пульсации — animation.

Классический fade-in: @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }, а затем animation: fadeIn 0.4s ease both. Ключевое слово both в fill-mode оставляет элемент в конечном состоянии, иначе он мигнёт обратно.

Для наведения обычно хватает transition — она дешевле и не требует @keyframes: .btn { transition: transform .2s ease, box-shadow .2s ease; } .btn:hover { transform: translateY(-2px); }. Если нужен непрерывный эффект (пульсация, мерцание), тогда уже подключайте animation с infinite.

Добавьте значение infinite в свойство animation: animation: pulse 1.5s ease-in-out infinite. Так делают лоадеры, пульсирующие точки и мигающие индикаторы. Чтобы движение шло туда-обратно без рывка на стыке, добавьте alternate — анимация будет проигрываться в обратную сторону через раз.

Плавно и дёшево анимируются transform и opacity — их браузер считает на видеокарте, не пересобирая вёрстку. А вот width, height, margin, top и left заставляют пересчитывать раскладку на каждом кадре, и на слабых устройствах анимация начинает дёргаться. Сдвиг делайте через transform: translate(), а не через left.

Плавность задаёт функция времени. Linear даёт механическое равномерное движение, ease-in-out — естественный разгон и торможение. Если нужна своя кривая, подберите её в генераторе cubic-bezier и подставьте в animation-timing-function.

Часть людей отключает анимации в системе из-за укачивания. Уважайте эту настройку через медиазапрос: @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; } }. Это требование доступности, и его легко забыть.