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.
/* дорого: 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;
}
}