CSS animation и @keyframes — анимации без JavaScript

CSS animation позволяет создавать анимации без JavaScript. Принцип: описываешь ключевые кадры через @keyframes, потом применяешь анимацию к элементу. Загрузчики, плавное появление, пульсация, встряска — всё это чистый CSS.

Вся рубрика CSS: уроки, примеры и справочник по стилям

@keyframes — описание анимации

@keyframes задаёт ключевые кадры анимации — состояния элемента в определённые моменты времени. from/to — начало и конец. Или проценты для точного контроля.

/* from / to — простейший случай */
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Проценты — детальный контроль */
@keyframes slideIn {
  0%   { transform: translateX(-100%); opacity: 0; }
  80%  { transform: translateX(10px);  opacity: 1; }
  100% { transform: translateX(0);     opacity: 1; }
}

/* Одинаковые значения в нескольких точках */
@keyframes bounce {
  0%, 100% { transform: translateY(0); }
  50%       { transform: translateY(-30px); }
}

/* Несколько свойств */
@keyframes highlight {
  0%   { background-color: transparent; transform: scale(1); }
  50%  { background-color: #fef08a;     transform: scale(1.02); }
  100% { background-color: transparent; transform: scale(1); }
}
Схема keyframes CSS: 0%, 50% и 100% показывают изменение transform и opacity
@keyframes задаёт состояния элемента во времени: от стартового кадра к финальному.

animation — свойства применения

/* Развёрнутая запись */
.element {
  animation-name:            fadeIn;   /* имя @keyframes */
  animation-duration:        0.5s;     /* длительность одного цикла */
  animation-timing-function: ease;     /* кривая скорости */
  animation-delay:           0.2s;     /* задержка перед стартом */
  animation-iteration-count: 1;        /* количество повторений */
  animation-direction:       normal;   /* направление */
  animation-fill-mode:       forwards; /* состояние до/после */
  animation-play-state:      running;  /* running или paused */
}

/* Shorthand: name duration timing delay count direction fill */
.element {
  animation: fadeIn 0.5s ease 0.2s 1 normal forwards;
}

/* Минимум: name + duration */
.spinner {
  animation: spin 1s linear infinite;
}
Панель свойств CSS animation: name, duration, timing-function, delay, iteration-count, direction, fill-mode, play-state
Свойства animation управляют именем, длительностью, задержкой, повторами и поведением после окончания.

animation-iteration-count — повторения

.element { animation-iteration-count: 1; }        /* один раз (по умолчанию) */
.element { animation-iteration-count: 3; }        /* три раза */
.element { animation-iteration-count: infinite; } /* бесконечно */
.element { animation-iteration-count: 1.5; }      /* 1 и ещё половина цикла */

/* Практические примеры */
.spinner { animation: spin 0.8s linear infinite; }  /* крутится вечно */
.flash   { animation: flash 0.3s ease 3; }          /* мигает 3 раза */
.fade-in { animation: fadeIn 0.4s ease 1 forwards; }/* один раз, остаётся */
Схема animation-iteration-count: один цикл, три цикла, infinite и полтора цикла
animation-iteration-count задаёт, сколько циклов выполнит анимация.

animation-direction — направление

.a { animation-direction: normal; }          /* → → →  каждый цикл с начала */
.b { animation-direction: reverse; }         /* ← ← ←  каждый цикл с конца */
.c { animation-direction: alternate; }       /* → ← → ←  туда-обратно */
.d { animation-direction: alternate-reverse;}/* ← → ← →  обратно-туда */

/* alternate — для пульсации и дыхания */
@keyframes breathe {
  from { transform: scale(1); }
  to   { transform: scale(1.08); }
}
.breathing {
  animation: breathe 2s ease-in-out alternate infinite;
  /* Будет плавно увеличиваться и уменьшаться */
}
Схема animation-direction: normal, reverse, alternate и alternate-reverse
animation-direction управляет направлением циклов: вперёд, назад или туда-обратно.

animation-fill-mode — состояние до и после

/* none: после анимации элемент возвращается к исходным стилям */
.popup { animation: slideIn 0.3s ease; }
/* После 0.3s — снова пропадёт (вернётся к исходным) */

/* forwards: элемент остаётся в конечном состоянии @keyframes */
.appear {
  opacity: 0;  /* исходно невидимый */
  animation: fadeIn 0.5s ease forwards;
  /* После анимации: opacity: 1 — остаётся видимым */
}

/* backwards: применить начальное состояние @keyframes сразу */
/* Полезно при animation-delay, чтобы не мелькало */
.delayed {
  animation: fadeIn 0.5s ease 1s backwards;
  /* Пока идёт задержка (1s) — уже opacity: 0, не мелькает */
}

/* both: forwards + backwards */
.smooth {
  animation: slideUp 0.4s ease 0.2s both;
  /* Применяет from сразу (нет мелькания при delay) */
  /* И остаётся в to после окончания */
}
Сравнение animation-fill-mode: none, forwards, backwards и both
animation-fill-mode помогает избежать мелькания при delay и сохранить финальное состояние.

Готовые анимации для копирования

/* 1. Fade In — появление */
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}
.fade-in {
  animation: fadeIn 0.5s ease forwards;
}

/* 2. Spin — спиннер загрузки */
@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
.spinner {
  display: inline-block;
  width: 40px;
  height: 40px;
  border: 4px solid #e5e7eb;
  border-top-color: #2563eb;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* 3. Pulse — пульсация (уведомления, акценты) */
@keyframes pulse {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%       { transform: scale(1.05); opacity: 0.8; }
}
.pulse {
  animation: pulse 2s ease-in-out infinite;
}

/* 4. Bounce — прыжок */
@keyframes bounceIn {
  0%   { transform: scale(0);     opacity: 0; }
  60%  { transform: scale(1.08);  opacity: 1; }
  80%  { transform: scale(0.95); }
  100% { transform: scale(1); }
}
.bounce-in {
  animation: bounceIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

/* 5. Shake — встряска (ошибки, неверный пароль) */
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  10%, 50%, 90% { transform: translateX(-8px); }
  30%, 70%      { transform: translateX(8px); }
}
.shake {
  animation: shake 0.5s ease;
}
/* Запуск: element.classList.add('shake') */
/* Удалить после окончания: */
/* element.addEventListener('animationend', () => el.classList.remove('shake')) */

/* 6. Skeleton shimmer — загрузочный скелет */
@keyframes shimmer {
  0%   { background-position: -400px 0; }
  100% { background-position: 400px 0; }
}
.skeleton {
  background: linear-gradient(
    90deg,
    #f0f0f0 25%,
    #e0e0e0 37%,
    #f0f0f0 63%
  );
  background-size: 800px 100%;
  animation: shimmer 1.4s ease infinite;
  border-radius: 4px;
  height: 16px;
}

/* 7. Float — парение */
@keyframes float {
  0%, 100% { transform: translateY(0); }
  50%       { transform: translateY(-12px); }
}
.floating {
  animation: float 3s ease-in-out infinite;
}

/* 8. Typing cursor — мигающий курсор */
@keyframes blink {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0; }
}
.cursor {
  display: inline-block;
  width: 2px;
  height: 1.2em;
  background: currentColor;
  margin-left: 2px;
  animation: blink 1s step-end infinite;
}
Галерея готовых CSS-анимаций: Fade In, Spin, Pulse, Bounce, Shake, Skeleton, Float, Typing cursor
Готовые CSS-анимации закрывают типовые задачи интерфейса: появление, загрузку, акцент и ошибки.

Несколько анимаций одновременно

/* Несколько анимаций через запятую */
.element {
  animation:
    fadeIn 0.5s ease forwards,         /* появляется */
    float 3s ease-in-out infinite 0.5s; /* потом парит */
}

/* Каскадное появление карточек */
.card { opacity: 0; }
.card:nth-child(1) { animation: fadeIn 0.4s ease 0.0s forwards; }
.card:nth-child(2) { animation: fadeIn 0.4s ease 0.1s forwards; }
.card:nth-child(3) { animation: fadeIn 0.4s ease 0.2s forwards; }
.card:nth-child(4) { animation: fadeIn 0.4s ease 0.3s forwards; }
Демонстрация нескольких CSS-анимаций одновременно: fadeIn плюс float и каскадное появление карточек
Несколько анимаций подключаются через запятую, а задержки создают каскадное появление карточек.

Управление анимацией через JavaScript

/* animation-play-state: paused / running */
.carousel {
  animation: slide 3s linear infinite;
}

/* Пауза при наведении */
.carousel:hover {
  animation-play-state: paused;
}

/* Запуск анимации через добавление класса */
.shake-animation {
  animation: none; /* по умолчанию нет анимации */
}

.shake-animation.is-shaking {
  animation: shake 0.5s ease;
}

// JavaScript
const form = document.querySelector('.shake-animation');

form.addEventListener('animationend', () => {
  form.classList.remove('is-shaking'); // убрать класс после окончания
});

function triggerShake() {
  form.classList.remove('is-shaking'); // сброс если уже идёт
  void form.offsetWidth; // force reflow
  form.classList.add('is-shaking');
}
Схема запуска CSS animation по клику через JavaScript: click, remove class, force reflow, add class, animationend
Для запуска по клику JavaScript добавляет класс с анимацией и снимает его после animationend.

prefers-reduced-motion — уважай пользователей

Некоторые пользователи отключают анимации в настройках ОС — из-за эпилепсии, укачивания или личных предпочтений. Браузер сообщает об этом через медиазапрос prefers-reduced-motion.

/* Отключить все анимации для пользователей, которые этого хотят */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Более избирательный подход */
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; } /* убрать вращение */
  .floating { animation: none; transform: none; } /* убрать парение */
  /* Оставить только критичные: индикаторы загрузки */
}
Сравнение обычного режима CSS animations и prefers-reduced-motion reduce
prefers-reduced-motion позволяет отключать или упрощать анимации для пользователей, которым это нужно.

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

Как запустить CSS animation по клику?

Базовый CSS не имеет прямого «запуска по клику», но это легко делается через JavaScript — добавляем класс с анимацией, потом убираем его после окончания. Либо используем состояние :focus или скрытый чекбокс :checked.

/* CSS */
.btn { /* обычная кнопка */ }
.btn.clicked {
  animation: pulse 0.3s ease;
}

/* JS */
btn.addEventListener('click', () => {
  btn.classList.remove('clicked');
  void btn.offsetWidth; // сброс (force reflow)
  btn.classList.add('clicked');
});

btn.addEventListener('animationend', () => {
  btn.classList.remove('clicked');
});

animation-fill-mode: forwards — что значит?

После окончания анимации элемент остаётся в состоянии последнего кадра (to или 100%). Без forwards элемент возвращается к исходным CSS-стилям — анимация «отматывается». Практически всегда при анимации появления (fadeIn, slideIn) нужен forwards, иначе элемент снова пропадёт.

CSS animation vs JavaScript animation — что быстрее?

CSS animation с transform и opacity выполняется в compositor thread — отдельном потоке, независимо от JavaScript. Это гарантирует 60fps даже если JS занят. JavaScript animation (requestAnimationFrame или GSAP) — гибче и позволяет сложную логику, но потенциально медленнее если не использовать transform. Итог: для простых UI-анимаций — CSS. Для сложных последовательностей, физики, интерактивных сцен — GSAP или Web Animations API.

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x