Перейти к основному содержимому

CSS-анимации — готовые эффекты

Готовые одностраничные примеры: скопировали HTML в файл, открыли в браузере — эффект уже работает. Ищете «css fade in», «анимация появления блока», «loader spinner css», «shimmer skeleton», «кнопка hover transition», «css shake error», «keyframes пример» — ниже код с разбором каждой важной строки, как в примерах Turtle и готовых макетах HTML+CSS.

Под каждым блоком — зачем свойство, как браузер проигрывает кадры, типичные ошибки новичков и что поменять для эксперимента.


Кому подойдёт эта страница

Школьникам — fade in для презентации, спиннер «загрузка» для проекта по информатике.
Студентам — лабораторная по вебу, курсовой лендинг, портфолио.
Самоучкам — первый живой интерфейс без JavaScript и без фреймворков.
Кто гуглит перед экзаменом — короткий рабочий код вместо десяти вкладок Stack Overflow.


Основы CSS-анимаций

С чего начать

Теория — в Анимации, переходы и трансформации. Каркас страницы и сетка — HTML + CSS — готовые макеты. Кнопки, карточки и модальные окна — UI-компоненты на CSS. Шпаргалка «что анимировать / чего избегать» — Практические рекомендации по CSS.

Загрузка HTML-песочницы…

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

Загрузка transitions…

Мини-симулятор показывает, как duration и timing-function меняют отклик кнопки на наведение и клик.


Как запустить пример за 30 секунд

  1. Скопируйте весь блок (от <!DOCTYPE html> до </html>).
  2. Вставьте в Блокнот / VS Code / Notepad++.
  3. Сохраните как anim.html (расширение .html, не .txt).
  4. Откройте двойным щелчком или перетащите в Chrome / Edge / Firefox.
  5. Не видите эффект — обновите страницу (F5). Всё ещё пусто — проверьте, что скопировали @keyframes выше или ниже класса, но внутри <style>.
Где правитьЧто менять для эксперимента
0.6s, 0.5sСкорость — меньше число, быстрее движение
translateY(24px)Дальность сдвига
ease, ease-out, linearХарактер ускорения
infiniteУберите — анимация один раз
цвета #2563ebЛюбой hex с htmlcolorcodes.com

Базовые термины

ТерминПростыми словами
transition«Если свойство вдруг изменилось — меняй его плавно за N секунд»
@keyframesСценарий: «на 0% элемент такой, на 50% — такой, на 100% — такой»
animationЗапуск сценария @keyframes по таймеру (даже без клика и hover)
transformСдвиг, поворот, масштаб без пересчёта всей страницы — обычно плавнее
opacityПрозрачность 0 (невидим) … 1 (полностью видим)
forwardsПосле конца анимации остаться в последнем кадре
infiniteПовторять сценарий бесконечно (спиннер, пульс)
animation-delayПауза перед стартом; у второго элемента — «волна»
prefers-reduced-motionНастройка ОС «уменьшить движение» — отключаем декор ради доступности

Transition или @keyframes — что выбрать

СитуацияИнструментПример из статьи
Навели мышь, нажали Tab, сменили классtransitionКнопка hover
Элемент сам «оживает» при загрузке@keyframes + animationFade in
Бесконечная загрузка@keyframes + infiniteСпиннер
Несколько элементов по очередиодин @keyframes, разные delayStagger-список

Мысленная модель. transitionдверь с доводчиком: толкнули (сменили стиль) — плавно закрылась. @keyframesмультфильм: браузер сам листает кадры по расписанию.


Как работать с примерами

  1. Сначала запустите код как есть — убедитесь, что работает.
  2. Меняйте одно свойство за раз (скорость, цвет, translateY).
  3. Сломали — верните исходник из статьи.
  4. Готовый эффект вставьте в макет страницы — замените содержимое <body> или добавьте класс к карточке.
Запись animation в одну строку

animation: fadeIn 0.6s ease forwards; читается так:
fadeIn — имя сценария из @keyframes
0.6s — длительность одного прохода
ease — плавность (мягкий старт и финиш)
forwards — после конца остаться в последнем кадре


Обязательный каркас

Любой пример ниже можно собрать на этом фундаменте.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS-анимация</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body {
margin: 0;
min-height: 100dvh;
padding: 1.5rem;
font-family: system-ui, sans-serif;
line-height: 1.5;
background: #f8fafc;
color: #1e293b;
}

@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
</style>
</head>
<body>
<!-- сюда разметка и стили эффекта -->
</body>
</html>

Разбор по строкам.

ФрагментСмысл
<!DOCTYPE html>Режим HTML5 — браузер рисует страницу предсказуемо
<meta charset="UTF-8">Кириллица в <title> и тексте
viewportНа телефоне страница не «уменьшенный десктоп»
box-sizing: border-boxpadding входит в ширину — сетка не ломается
body &#123; margin: 0 &#125;Убирает белую полоску у края окна
min-height: 100dvhМинимум на всю высоту экрана; dvh учитывает панель браузера на телефоне
prefers-reduced-motion: reduceЕсли в системе включено «уменьшить движение» — почти отключаем анимации
0.01ms !importantКонтент остаётся, движение почти незаметно — это правильнее, чем display: none

Типичные ошибки.

  • Сохраняют файл как anim.txt — браузер покажет код текстом, а не страницу.
  • Кладут @keyframes вне <style> — правило не сработает.
  • Пишут animation: fadeIn без @keyframes fadeIn { … } — браузер не знает, что проигрывать.

Попробуйте сами. В Windows включите Параметры → Специальные возможности → Визуальные эффекты → Анимация в Windows (выкл.) и перезагрузите страницу — каркас должен уважать настройку.


Стартовые эффекты

Простые эффекты, которые чаще всего ищут в Google и Яндексе.


Плавное появление (fade in)

Задача. Карточка, баннер или текст плавно проявляются при открытии страницы.

Частые запросы: css fade in, анимация появления css, opacity animation, плавное появление блока.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fade in</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body {
margin: 0;
min-height: 100dvh;
display: grid;
place-items: center;
font-family: system-ui, sans-serif;
background: #eef2ff;
}
.card {
padding: 1.5rem 2rem;
background: #fff;
border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
animation: fadeIn 0.6s ease forwards;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
</head>
<body>
<article class="card">
<h1 style="margin: 0 0 0.5rem; font-size: 1.25rem;">Привет!</h1>
<p style="margin: 0; color: #64748b;">Карточка плавно появилась.</p>
</article>
</body>
</html>

Разбор CSS — что за что отвечает.

СвойствоЗачем здесь
display: grid + place-items: center на bodyКарточка по центру экрана без position: absolute
animation: fadeIn 0.6s ease forwardsЗапуск сценария fadeIn, 0,6 с, плавность ease, финал сохраняется
@keyframes fadeInИмя должно совпадать с первым словом в animation
from &#123; opacity: 0 &#125;Старт: полностью прозрачный
to &#123; opacity: 1 &#125;Финиш: полностью видимый
forwardsБез него после 0,6 с элемент может «мигнуть» и вернуться к opacity: 1 по умолчанию — но при других эффектах без forwards часто исчезает

Как браузер проигрывает анимацию (по шагам).

  1. Страница загрузилась — .card уже в DOM.
  2. Браузер видит animation: fadeIn … и ищет @keyframes fadeIn.
  3. 0 ms — рисует кадр from (opacity: 0), карточка невидима.
  4. 0 … 600 ms — плавно интерполирует прозрачность от 0 до 1.
  5. 600 ms — кадр to; благодаря forwards карточка остаётся видимой.

HTML. <article class="card"> — самостоятельный блок контента; для урока и портфолио лучше, чем безликий <div>.

Типичные ошибки.

  • Опечатка в имени: animation: fade-in и @keyframes fadeIn — анимация не запустится.
  • Ставят opacity: 0 в .card и забывают forwards — после анимации элемент снова прозрачный.
  • Ожидают fade in при скролле — для этого нужен JavaScript или animation-timeline (продвинутый CSS); этот пример — при загрузке.

Попробуйте сами.

  • 0.6s2s — медленное проявление.
  • easelinear — равномерное, «роботное» появление.
  • Добавьте в from: transform: scale(0.95) и в to: transform: scale(1) — лёгкое увеличение вместе с fade.

Появление снизу (slide up)

Задача. Уведомление «Сохранено», toast, карточка выезжает снизу и проявляется.

Частые запросы: css slide up animation, translateY animation, появление снизу css.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Slide up</title>
<style>
body {
margin: 0;
min-height: 100dvh;
display: grid;
place-items: center;
font-family: system-ui, sans-serif;
background: #f0fdf4;
}
.toast {
padding: 1rem 1.25rem;
background: #166534;
color: #fff;
border-radius: 8px;
animation: slideUp 0.5s ease-out forwards;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(24px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head>
<body>
<p class="toast">Сохранено успешно</p>
</body>
</html>

Разбор CSS.

СвойствоЗачем здесь
translateY(24px) в fromЭлемент ниже финальной позиции на 24 px — создаёт эффект «подъёма»
translateY(0) в toФинальная позиция — там, где блок стоит в потоке документа
ease-outБыстрый старт, мягкая остановка — toast «приземляется»
opacity + transform вместеИ выезд, и проявление — профессиональный UX-паттерн

Почему transform, а не margin-top или top.

  • margin-top и top двигают layout — соседние блоки прыгают, браузер пересчитывает всю страницу.
  • transform: translateY() только рисует элемент в другом месте — соседи на месте, анимация обычно плавнее.

Как браузер проигрывает анимацию.

  1. from: невидим (opacity: 0), сдвинут вниз на 24 px.
  2. За 0,5 с одновременно поднимает и делает непрозрачным.
  3. to: на месте, полностью видим — forwards фиксирует результат.

Типичные ошибки.

  • Анимируют top: 24pxtop: 0 у position: absolute — работает, но сложнее вёрстка и чаще лаги.
  • translateY(-24px) в from — блок упадёт сверху, а не поднимется снизу (знак важен).
  • Слишком большой сдвиг (120px) на мобильном — toast «улетает» за экран.

Попробуйте сами. 24px8px — едва заметный сдвиг, только fade «с характером». Добавьте box-shadow в to — toast «отрывается» от фона.


Пульсация (pulse)

Задача. Красная точка «онлайн», кнопка «Записаться», индикатор — мягко пульсирует и привлекает взгляд.

Частые запросы: css pulse animation, pulsating dot css, scale animation infinite.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pulse</title>
<style>
body {
margin: 0;
min-height: 100dvh;
display: grid;
place-items: center;
font-family: system-ui, sans-serif;
}
.dot {
width: 16px;
height: 16px;
border-radius: 50%;
background: #ef4444;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.35); opacity: 0.65; }
}
</style>
</head>
<body>
<span class="dot" aria-hidden="true"></span>
</body>
</html>

Разбор CSS.

СвойствоЗачем здесь
width/height: 16px + border-radius: 50%Круг из квадрата
infiniteЦикл без остановки — пока страница открыта
ease-in-outМягкое ускорение и замедление — «дыхание», не мигание
0%, 100%Один и тот же кадр в начале и конце — цикл бесшовный
50%Середина цикла — максимум размера, минимум прозрачности
scale(1.35)Увеличение на 35% — заметно, но не карикатурно

Как браузер проигрывает анимацию.

  1. 0 s — круг обычного размера.
  2. 0,75 s (середина 1,5 s) — крупнее и полупрозрачный.
  3. 1,5 s — снова исходный вид → цикл повторяется.

HTML. aria-hidden="true" — скринридер не озвучивает декоративную точку.

Типичные ошибки.

  • Только opacity без scale — мигает, как сигнализация; для «онлайн» лучше комбо.
  • scale(2) — слишком агрессивно; начните с 1.21.4.
  • Пульс на всей карточке infinite — отвлекает; лучше на маленьком badge.

Попробуйте сами. Поменяйте 1.5s на 3s — спокойный медленный pulse. Цвет #ef4444#22c55e — «онлайн» вместо «ошибка».


Кнопка с hover и focus (transition)

Задача. Кнопка приподнимается при наведении, нажимается при клике, видна при Tab с клавиатуры.

Частые запросы: css button hover effect, transition transform, кнопка анимация css, hover поднять кнопку.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Кнопка hover</title>
<style>
body {
margin: 0;
min-height: 100dvh;
display: grid;
place-items: center;
font-family: system-ui, sans-serif;
background: #fafafa;
}
.btn {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 10px;
background: #2563eb;
color: #fff;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 14px rgba(37, 99, 235, 0.35);
transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(37, 99, 235, 0.4);
background: #1d4ed8;
}
.btn:focus-visible {
outline: 3px solid #93c5fd;
outline-offset: 2px;
}
.btn:active {
transform: translateY(0);
box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3);
}
</style>
</head>
<body>
<button type="button" class="btn">Отправить</button>
</body>
</html>

Разбор CSS — цепочка состояний.

СелекторЧто происходит
.btn (обычное)Базовый вид + объявление transition — «как плавно менять свойства»
.btn:hoverМышь над кнопкой — подъём на 2 px, тень сильнее, фон темнее
.btn:focus-visibleФокус с клавиатуры (Tab) — синее кольцо; после клика мышью кольцо не висит
.btn:activeКнопка нажата — возврат вниз, тень слабее — эффект «вдавливания»

Разбор transition — порядок важен.

transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
  • transform 0.2s — движение вверх-вниз за 0,2 секунды.
  • box-shadow 0.2s — тень меняется синхронно — кнопка «отрывается» от фона.
  • background-color 0.2s — цвет не переключается мгновенно.
  • ease — чуть медленнее в начале и конце — приятнее глазу, чем linear.

Почему transition на .btn, а не на :hover.

Браузер должен знать правила плавности до смены состояния. Если написать transition только в :hover, при уходе мыши возврат будет резким.

Как это работает при наведении.

  1. Курсор вошёл на кнопку → применился .btn:hover.
  2. transform изменился с none на translateY(-2px) — за 0,2 s.
  3. Курсор ушёл → стили :hover снялись → за 0,2 s кнопка вернулась.

Типичные ошибки.

  • transition: all — браузер следит за всеми свойствами, включая дорогие; перечисляйте явно.
  • Только :hover без :focus-visible — с клавиатуры кнопку не видно (плохо для доступности и экзамена по вебу).
  • transform: translateY(-20px) — кнопка «улетает»; для UI хватит 2–4 px.

Попробуйте сами. 0.2s0.6s — «желе». Уберите :active — пропадёт ощущение нажатия.


Загрузка и ожидание

Эффекты «подождите, идёт загрузка» — частый запрос в учебных проектах и на собеседованиях junior.


Крутящийся спиннер

Задача. Показать, что сайт ждёт ответ сервера или грузит файл.

Частые запросы: css loading spinner, loader animation, крутящийся кружок css, rotate animation infinite.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Spinner</title>
<style>
body {
margin: 0;
min-height: 100dvh;
display: grid;
place-items: center;
font-family: system-ui, sans-serif;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #e2e8f0;
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="spinner" role="status" aria-label="Загрузка"></div>
</body>
</html>

Разбор CSS — из чего складывается «кольцо».

СвойствоЗачем здесь
border: 4px solid #e2e8f0Серое кольцо по всему перimeter
border-top-color: #3b82f6Только верхняя дуга синяя — глаз видит «сектор»
border-radius: 50%Квадрат 40×40 превращается в круг
rotate(360deg)Полный оборот за один цикл
linearРавномерная скорость — для спиннера это стандарт
0.8sБыстро enough, не раздражает

Как браузер проигрывает анимацию.

  1. Каждые 0,8 s элемент поворачивается от 0° до 360°.
  2. infinite — следующий оборот сразу после предыдущего.
  3. Синяя дуга «бежит» по кругу — классический loader.

HTML — доступность.

АтрибутЗачем
role="status"Область статуса для скринридера
aria-label="Загрузка"Озвучка «Загрузка» для незрячих пользователей

Типичные ошибки.

  • Крутят через border-color на всех сторонах по очереди — сложнее; паттерн «серое кольцо + цветной top» проще.
  • animation: spin 0.8s ease — спиннер замирает на секунду между оборотами; нужен linear.
  • Забывают border-radius: 50% — крутится квадрат.

Попробуйте сами. border-top-colorborder-right-color — дуга смещена. 40px24px — компактный спиннер для кнопки.


Три прыгающие точки

Задача. Индикатор «печатает…», «бот думает», загрузка чата.

Частые запросы: typing indicator css, three dots animation, bounce animation css.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Точки загрузки</title>
<style>
body {
margin: 0;
min-height: 100dvh;
display: grid;
place-items: center;
font-family: system-ui, sans-serif;
}
.dots {
display: flex;
gap: 0.4rem;
}
.dots span {
width: 10px;
height: 10px;
border-radius: 50%;
background: #6366f1;
animation: bounce 0.6s ease-in-out infinite;
}
.dots span:nth-child(2) { animation-delay: 0.15s; }
.dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes bounce {
0%, 80%, 100% { transform: translateY(0); }
40% { transform: translateY(-10px); }
}
</style>
</head>
<body>
<div class="dots" aria-hidden="true">
<span></span><span></span><span></span>
</div>
</body>
</html>

Разбор CSS.

СвойствоЗачем здесь
display: flex + gapТри точки в ряд с равным промежутком
Один @keyframes bounce на все <span>Не дублируем код — один сценарий
:nth-child(2) &#123; animation-delay: 0.15s &#125;Вторая точка стартует позже — волна
:nth-child(3) &#123; animation-delay: 0.3s &#125;Третья ещё позже
0%, 80%, 100% на одном уровнеБольшую часть цикла точка на земле — пауза между прыжками
40% — пик прыжкаКороткий всплеск в середине цикла

Как браузер проигрывает волну.

  1. Первая точка прыгает в момент 0.
  2. Вторая — с задержкой 0,15 s — фаза сдвинута.
  3. Третья — 0,3 s — глаз видит «бегущую» волну.

Типичные ошибки.

  • Три разных @keyframes — лишний код; хватит одного + delay.
  • Одинаковый delay на всех — точки прыгают синхронно, не «typing».
  • translateY(10px) вместо -10px — точки проваливаются вниз.

Попробуйте сами. 0.15s и 0.3s0.1s и 0.2s — более частая волна. Четыре точки — добавьте <span> и правило для :nth-child(4).


Skeleton shimmer

Задача. Серые полоски имитируют текст, пока данные грузятся (VK, Ozon, YouTube).

Частые запросы: skeleton loading css, shimmer effect, placeholder animation css.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Shimmer</title>
<style>
body {
margin: 0;
padding: 2rem;
font-family: system-ui, sans-serif;
background: #fff;
}
.skeleton {
max-width: 320px;
}
.skeleton__line {
height: 14px;
margin-bottom: 12px;
border-radius: 6px;
background: linear-gradient(
90deg,
#e2e8f0 0%,
#f1f5f9 50%,
#e2e8f0 100%
);
background-size: 200% 100%;
animation: shimmer 1.4s ease-in-out infinite;
}
.skeleton__line--short { width: 60%; }
.skeleton__line--title { height: 20px; width: 80%; margin-bottom: 16px; }
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
</style>
</head>
<body>
<div class="skeleton" aria-busy="true" aria-label="Загрузка контента">
<div class="skeleton__line skeleton__line--title"></div>
<div class="skeleton__line"></div>
<div class="skeleton__line"></div>
<div class="skeleton__line skeleton__line--short"></div>
</div>
</body>
</html>

Разбор CSS — почему «блик» едет.

СвойствоЗачем здесь
linear-gradient(90deg, …)Полоска: серый → светлый → серый слева направо
background-size: 200% 100%Градиент в два раза шире блока — есть куда «ездить»
background-position: 200% 0-200% 0Сдвигаем фон — светлая полоса пробегает по серой
--title / --shortРазная ширина и высота — как заголовок и строки текста
aria-busy="true"Скринридер: контент ещё загружается

Как браузер проигрывает shimmer.

  1. Фон шире видимой полоски.
  2. За 1,4 s позиция фона смещается с правого края к левому.
  3. Глаз видит «блик», бегущий по серым линиям.

Типичные ошибки.

  • Забыли background-size: 200% — блик не двигается, только статичный градиент.
  • Анимируют width полоски — тяжело; здесь двигается фон, не layout.
  • Shimmer на весь экран infinite на слабом телефоне — лаги; для учебы норм, в проде — осторожно.

Попробуйте сами. Светлая полоса в градиенте на 80% вместо 50% — узкий блик. Добавьте border-radius: 50% и height: 48px; width: 48px — skeleton-аватар.


Полоска прогресса

Задача. Полоска заполняется до 75% — загрузка файла, шаг мастера, HP в игре.

Частые запросы: css progress bar animation, width animation keyframes.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Progress bar</title>
<style>
body {
margin: 0;
min-height: 100dvh;
display: grid;
place-items: center;
padding: 1rem;
font-family: system-ui, sans-serif;
}
.progress {
width: min(100%, 280px);
height: 8px;
background: #e2e8f0;
border-radius: 999px;
overflow: hidden;
}
.progress__bar {
height: 100%;
width: 0;
background: linear-gradient(90deg, #22c55e, #16a34a);
border-radius: inherit;
animation: fillBar 2.5s ease-out forwards;
}
@keyframes fillBar {
to { width: 75%; }
}
</style>
</head>
<body>
<div class="progress" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" aria-label="Загрузка">
<div class="progress__bar"></div>
</div>
</body>
</html>

Разбор CSS.

СвойствоЗачем здесь
.progress — серая «дорожка»Фон, виден незаполненный участок
overflow: hiddenЗелёная полоска не вылезает за скругление
width: 0 в началеСтарт с пустой полосы
@keyframes fillBar &#123; to &#123; width: 75% &#125; &#125;За 2,5 s ширина растёт до 75% родителя
border-radius: inheritВнутренний бар повторяет скругление дорожки
ease-outБыстро в начале, медленнее к концу — «дожим» загрузки

Почему здесь width, а не transform.

Для узкой полоски 8 px пересчёт layout дешёвый. В реальном приложении процент часто задаёт JavaScript (style.width = '45%'). CSS-анимация показывает идею без скриптов.

HTML — доступность.

role="progressbar" + aria-valuenow="75" — скринридер озвучит прогресс. В живом приложении valuenow обновляют из JS.

Типичные ошибки.

  • Нет overflow: hidden — зелёный прямоугольник торчит за скруглённую дорожку.
  • width: 75% сразу в .progress__bar без анимации — полоска статична.
  • Анимировать width у широкого sidebar — может лагать; для progress bar это норма.

Попробуйте сами. 75%100% — полное заполнение. 2.5s0.8s — быстрая загрузка.


Внимание и обратная связь


Тряска при ошибке (shake)

Задача. Поле формы дёргается, если email неверный — понятная обратная связь без alert().

Частые запросы: css shake animation, input error animation, form shake css.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Shake</title>
<style>
body {
margin: 0;
min-height: 100dvh;
display: grid;
place-items: center;
font-family: system-ui, sans-serif;
}
.field {
padding: 0.65rem 0.85rem;
border: 2px solid #ef4444;
border-radius: 8px;
font-size: 1rem;
animation: shake 0.45s ease;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
20% { transform: translateX(-8px); }
40% { transform: translateX(8px); }
60% { transform: translateX(-6px); }
80% { transform: translateX(6px); }
}
</style>
</head>
<body>
<input class="field" type="email" value="не-email" aria-invalid="true">
</body>
</html>

Разбор CSS — почему «дёргается».

КадрtranslateXЭффект
0%, 100%0Центр — покой
20%−8pxРывок влево
40%+8pxРывок вправо
60%−6pxЗатухание
80%+6pxЗатухание

Амплитуда убывает (8 → 6 px) — тряска «успокаивается», как пружина.

Как связать с JavaScript (идея).

form.addEventListener('submit', (e) => {
if (!emailValid) {
field.classList.add('field--error');
field.addEventListener('animationend', () => {
field.classList.remove('field--error');
}, { once: true });
}
});
.field--error { animation: shake 0.45s ease; }

Класс вешают на момент ошибки; после animationend снимают — можно трясти снова при повторной ошибке.

Типичные ошибки.

  • infinite на shake — поле трясётся вечно, пользователь в панике.
  • translateX(50px) — слишком агрессивно для input.
  • Тряска без красной рамки — не все понимают, что это ошибка.

Попробуйте сами. Только 20% и 40% кадры — одно «нет» вместо двух. Добавьте background: #fef2f2 — розовый фон ошибки.


Парящий декор (float)

Задача. Иконка или иллюстрация на лендинге мягко покачивается вверх-вниз.

Частые запросы: floating animation css, hover float effect, translateY infinite.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Float</title>
<style>
body {
margin: 0;
min-height: 100dvh;
display: grid;
place-items: center;
font-family: system-ui, sans-serif;
background: linear-gradient(180deg, #dbeafe, #eff6ff);
}
.float-icon {
font-size: 4rem;
animation: floatY 3s ease-in-out infinite;
}
@keyframes floatY {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-14px); }
}
</style>
</head>
<body>
<div class="float-icon" aria-hidden="true">🚀</div>
</body>
</html>

Разбор CSS.

СвойствоЗачем здесь
3sМедленный цикл — спокойный декор, не отвлекает
ease-in-outПлавный разворот в верхней и нижней точке
translateY(-14px)Подъём вверх; минус — вверх по экрану
infiniteБесконечное «парение» на hero-секции

Отличие от pulse. Pulse меняет размер и прозрачность. Float только двигает — объект «висит в воздухе».

Типичные ошибки.

  • Float на весь текст абзаца — читать невозможно; только иконка или картинка.
  • translateY(-80px) — «прыжки», не парение.
  • Анимировать top у position: absolute — layout страдает; transform предпочтительнее.

Попробуйте сами. Две иконки с animation-delay: 1.5s у второй — «вола» на лендинге. Замените emoji на <img src="…" alt="">.

Тот же приём — в UI-компонентах для декора hero-блока.


Последовательности и сложные сцены


Список с задержкой (stagger)

Задача. Пункты меню или карточки появляются по очереди — эффект «дорогого» интерфейса без библиотек.

Частые запросы: stagger animation css, animation-delay nth-child, список появление по очереди css.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Stagger list</title>
<style>
body {
margin: 0;
min-height: 100dvh;
padding: 2rem;
font-family: system-ui, sans-serif;
background: #fff;
}
.list { list-style: none; margin: 0; padding: 0; max-width: 20rem; }
.list li {
padding: 0.75rem 1rem;
margin-bottom: 0.5rem;
background: #f1f5f9;
border-radius: 8px;
opacity: 0;
transform: translateX(-16px);
animation: staggerIn 0.45s ease forwards;
}
.list li:nth-child(1) { animation-delay: 0.05s; }
.list li:nth-child(2) { animation-delay: 0.15s; }
.list li:nth-child(3) { animation-delay: 0.25s; }
.list li:nth-child(4) { animation-delay: 0.35s; }
@keyframes staggerIn {
to {
opacity: 1;
transform: translateX(0);
}
}
</style>
</head>
<body>
<ul class="list">
<li>Первый пункт</li>
<li>Второй пункт</li>
<li>Третий пункт</li>
<li>Четвёртый пункт</li>
</ul>
</body>
</html>

Разбор CSS.

СвойствоЗачем здесь
opacity: 0 + translateX(-16px) до анимацииНачальное состояние — невидим, слева
@keyframes staggerIn &#123; to &#123; … &#125; &#125;Только конечный кадр — from берётся из стилей элемента
forwardsПосле появления пункт остаётся видимым
:nth-child(n) &#123; animation-delay: … &#125;Каждый следующий стартует на 0,1 s позже
Шаг 0,1 s (0.05, 0.15, 0.25…)Ритм «каскада»

Как браузер проигрывает stagger.

  1. t = 0,05 s — стартует первый <li>.
  2. t = 0,15 s — второй (первый уже почти на месте).
  3. К t ≈ 0,8 s все четыре пункта видимы.

Масштаб на много пунктов (CSS-переменная).

.list li {
animation-delay: calc(var(--i, 0) * 0.08s);
}
<li style="--i: 1"></li>
<li style="--i: 2"></li>

Типичные ошибки.

  • Забыли opacity: 0 в .list li — пункты видны до анимации, stagger теряет смысл.
  • Одинаковый delay — всё появляется разом.
  • animation-delay: 2s на десятом пункте — пользователь уйдёт раньше.

Попробуйте сами. translateX(-16px)translateY(12px) — каскад снизу. 0.45s0.25s — быстрее, «снэппи».


Модальное окно — затемнение и масштаб

Задача. Диалог плавно открывается: фон темнеет, окно чуть увеличивается.

Частые запросы: modal fade in css, popup animation scale, overlay opacity animation.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Modal fade</title>
<style>
body {
margin: 0;
min-height: 100dvh;
font-family: system-ui, sans-serif;
}
.modal {
position: fixed;
inset: 0;
display: grid;
place-items: center;
padding: 1rem;
}
.modal__backdrop {
position: absolute;
inset: 0;
background: rgba(15, 23, 42, 0.55);
animation: fadeIn 0.25s ease forwards;
}
.modal__dialog {
position: relative;
width: min(100%, 22rem);
padding: 1.5rem;
background: #fff;
border-radius: 12px;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.2);
animation: scaleIn 0.3s ease-out 0.05s forwards;
opacity: 0;
transform: scale(0.92);
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes scaleIn {
to {
opacity: 1;
transform: scale(1);
}
}
</style>
</head>
<body>
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<div class="modal__backdrop"></div>
<div class="modal__dialog">
<h2 id="modal-title" style="margin: 0 0 0.5rem;">Подтверждение</h2>
<p style="margin: 0; color: #64748b;">Окно появилось с fade и лёгким scale.</p>
</div>
</div>
</body>
</html>

Разбор CSS — два слоя, две анимации.

ЭлементАнимацияСмысл
.modal__backdropfadeIn 0.25sЗатемнение фона
.modal__dialogscaleIn 0.3s … 0.05sОкно: задержка 0,05 s, рост из 92% + проявление

Разбор animation: scaleIn 0.3s ease-out 0.05s forwards.

  1. scaleIn — имя keyframes.
  2. 0.3s — длительность.
  3. ease-out — быстро выезжает, мягко останавливается.
  4. 0.05sdelay; фон успевает начать темнеть раньше окна.
  5. forwards — окно остаётся opacity: 1 и scale(1).

Разбор позиционирования.

СвойствоЗачем
.modal &#123; position: fixed; inset: 0 &#125;На весь экран поверх страницы
.modal__backdrop &#123; position: absolute; inset: 0 &#125;Заливка на фон модалки
.modal__dialog &#123; position: relative &#125;Окно выше backdrop в stacking order
display: grid; place-items: centerДиалог по центру

HTML — доступность.

role="dialog", aria-modal="true", aria-labelledby — минимум для модального окна. Открытие/закрытие по кнопке — в UI-компонентах + JavaScript.

Типичные ошибки.

  • Одна анимация на .modal — нельзя отдельно затемнить фон и масштабировать окно.
  • scale(0) в начале — окно «вырастает из точки», слишком драматично; 0.920.95 мягче.
  • Модалка без position: fixed — блок в потоке страницы, не поверх контента.

Попробуйте сами. 0.05s delay → 0.15s — окно явно «опаздывает». scale(0.92)scale(1.05) в начале — лёгкий overshoot (пружинка).


Набор переиспользуемых классов

Скопируйте в конец style.css — подключайте классы к любым элементам на готовой странице.

/* --- Появление --- */
.animate-fade-in { animation: fadeIn 0.6s ease forwards; }
.animate-slide-up { animation: slideUp 0.5s ease-out forwards; }
.animate-pulse { animation: pulse 2s ease-in-out infinite; }

@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}

/* --- Hover-кнопка --- */
.btn-motion {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.btn-motion:hover {
transform: translateY(-2px);
}

Разбор использования.

<div class="card animate-fade-in"></div>
<button type="button" class="btn btn-motion">Действие</button>
КлассКогда вешать
animate-fade-inКарточка, hero-текст при загрузке
animate-slide-upToast, popup снизу
animate-pulseBadge «live», кнопка CTA
btn-motionЛюбая кнопка с лёгким hover

Такой же набор — в UI-компоненты на CSS.


Шпаргалка — что копировать под задачу

НужноМинимальный код
Появление@keyframes + opacity + forwards
Движениеtransform: translate… / rotate / scale
Hover-кнопкаtransition на .btn + :hover &#123; transform &#125;
Бесконечный циклinfinite + linear (спиннер) или ease-in-out (float)
По очередиодин @keyframes + :nth-child(n) &#123; animation-delay &#125;
Уважение к ОС@media (prefers-reduced-motion: reduce) { … }

Производительность

Для движения и появления предпочитайте transform и opacity. Осторожно с бесконечным box-shadow, filter: blur и shimmer на весь экран. Учитывайте prefers-reduced-motion — каркас в начале статьи. Подробнее — Практические рекомендации по CSS и Доступность.


Что дальше

ЗадачаКуда идти
Целая страница с сеткой и шапкойHTML + CSS — готовые макеты
Страница на utility-классахTailwind — готовые блоки
Справочник по animation-*Анимации, переходы и трансформации
Карусель, табы, модалка + JSUI-компоненты, Виджеты на JavaScript
Рисование и игровой циклp5.js — примеры фигур
200 вопросов с ответами200 вопросов по CSS

См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").