Урок 42. Ошибки: Анимации и переходы: transition и @keyframes

📁 Раздел: Современный CSS ⏱️ Время изучения: ~80 мин 🎯 Сложность: Средняя
#transition #transition-property #transition-duration #transition-timing-function #transition-delay #cubic-bezier #steps #keyframes #animation #animation-name #animation-duration #animation-timing-function #animation-iteration-count #animation-fill-mode #animation-delay #animation-direction #transform #opacity #media

⚡ Кратко

`transition` плавно меняет свойства между состояниями, а `@keyframes` описывает самостоятельную анимацию. Разбираем duration, easing, iteration, fill-mode, производительные `transform`/`opacity` и `prefers-reduced-motion`.

1. Забыли transition-duration

Без длительности (по умолчанию 0s) перехода нет — значение перескакивает мгновенно. Это самая частая причина «почему не анимируется».

/* НЕ работает: длительность не задана */
.button { transition-property: transform; }
.button:hover { transform: scale(1.1); }   /* скачок, без плавности */
/* правильно: указали duration */
.button { transition: transform 180ms ease; }
.button:hover { transform: scale(1.1); }

2. transition на :hover вместо базового селектора

Если переход объявлен только в :hover, плавно работает лишь «вход», а «выход» (когда курсор ушёл) — резкий скачок, потому что в обычном состоянии перехода уже нет.

.card:hover { transition: transform .2s; transform: translateY(-4px); }
/* наведение плавное, возврат — рывком */
.card { transition: transform .2s; }       /* переход на базовом селекторе */
.card:hover { transform: translateY(-4px); } /* плавно в обе стороны */

3. Анимация дорогих свойств

Анимация width, height, top, left, margin заставляет браузер пересчитывать раскладку каждый кадр — движение дёргается. Для геометрии используйте transform, для прозрачности — opacity.

width 90→160
🐢 reflow
scaleX(1.4)
⚡ дёшево
/* дорого: reflow на каждом кадре */
.bad  { transition: width .3s; }
/* дёшево: композитинг на отдельном слое */
.good { transition: transform .3s; }

4. Состояние только мышью

Эффект на :hover без :focus/:focus-within недоступен с клавиатуры. Добавляйте фокус для интерактивных элементов (см. урок 41).

.button:hover,
.button:focus-visible { transform: translateY(-3px); }

5. Игнор prefers-reduced-motion

Бесконечные пульсы и большие сдвиги могут вызывать дискомфорт. Всегда давайте «тихий» вариант через медиазапрос (урок 38 о доступности).

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms;
    transition-duration: .01ms;
  }
}

Навигация