Переход = что + сколько + как
Три класса покрывают почти все случаи:
transition— анимировать типовой набор свойств (цвет, фон, границу, тень, трансформацию);duration-200— длительность в миллисекундах;ease-out— кривая ускорения.
<div class="flex flex-wrap gap-3">
<button class="rounded-md bg-sky-600 px-4 py-2 text-sm text-white">без transition</button>
<button class="rounded-md bg-sky-600 px-4 py-2 text-sm text-white transition-colors duration-200 hover:bg-sky-800">transition-colors 200мс</button>
<button class="rounded-md bg-sky-600 px-4 py-2 text-sm text-white transition-colors duration-700 hover:bg-sky-800">duration-700 — слишком долго</button>
</div>
Наведите на все три кнопки: первая переключается мгновенно, вторая — приятно,
третья ощущается «залипшей». Это и есть практическая разница между
значениями duration.
Переход — как закрывание двери с доводчиком. Без доводчика дверь хлопает: пользователь не понимает, что произошло. С правильным доводчиком движение читается. С слишком тугим — вы стоите и ждёте, пока дверь закроется, вместо того чтобы идти дальше.
Кривые ускорения
| Класс | Поведение | Когда |
|---|---|---|
ease-linear | равномерно | бесконечные анимации: спиннер, прогресс |
ease-in | медленно → быстро | исчезновение, уход за экран |
ease-out | быстро → медленно | появление: самый частый выбор |
ease-in-out | плавно с обоих концов | перемещение внутри экрана |
ease-out, исчезновение — ease-in. Так объект
«влетает» энергично и «уходит» мягко — в жизни предметы ведут себя похоже.Трансформации: движение без пересчёта раскладки
transform двигает, поворачивает и масштабирует элемент,
не трогая соседей — браузер не пересчитывает раскладку, а значит, анимация
не «дёргается».
<div class="flex flex-wrap items-center gap-6">
<div class="size-16 rounded-lg bg-indigo-500 transition-transform duration-200 hover:scale-110"></div>
<div class="size-16 rounded-lg bg-emerald-500 transition-transform duration-200 hover:-translate-y-2"></div>
<div class="size-16 rounded-lg bg-amber-500 transition-transform duration-300 hover:rotate-12"></div>
<div class="size-16 rounded-lg bg-rose-500 transition-transform duration-200 hover:skew-x-6"></div>
</div>
Слева направо: hover:scale-110, hover:-translate-y-2,
hover:rotate-12, hover:skew-x-6. Точку отсчёта задаёт
origin-*: например, origin-bottom для «вырастающего»
элемента.
Готовые анимации
| Класс | Что делает | Где применяют |
|---|---|---|
animate-spin | бесконечное вращение | индикатор загрузки |
animate-pulse | мигание прозрачностью | скелетоны |
animate-ping | расходящееся кольцо | привлечь внимание к точке |
animate-bounce | подпрыгивание | указатель «листайте вниз» |
animate-none | отключить | переопределение |
<div class="flex flex-wrap items-center gap-6">
<span class="inline-block size-6 animate-spin rounded-full border-2 border-slate-300 border-t-slate-900"></span>
<div class="w-40 space-y-2">
<div class="h-3 animate-pulse rounded bg-slate-200"></div>
<div class="h-3 w-2/3 animate-pulse rounded bg-slate-200"></div>
</div>
<span class="relative flex size-3">
<span class="absolute inline-flex size-full animate-ping rounded-full bg-emerald-400 opacity-75"></span>
<span class="relative inline-flex size-3 rounded-full bg-emerald-500"></span>
</span>
<span class="animate-bounce text-2xl">↓</span>
</div>
Своя анимация
Собственные ключевые кадры описываются обычным CSS, а имя попадает
в тему — после этого доступен класс animate-fade-up:
/* src/index.css */
@import "tailwindcss";
@theme {
--animate-fade-up: fade-up 0.25s ease-out;
}
@keyframes fade-up {
from { opacity: 0; transform: translateY(0.5rem); }
to { opacity: 1; transform: translateY(0); }
}
Этот текст появился с анимацией fade-up
<div class="rounded-lg border border-slate-200 bg-white p-4">
<p class="animate-fade-up text-sm text-slate-700">Этот текст появился с анимацией fade-up</p>
</div>
Появление элементов: starting
Долгое время анимировать появление можно было только через JavaScript.
Теперь есть @starting-style, а в Tailwind — вариант
starting:: он задаёт значения, с которых элемент начинает
существование.
<div class="opacity-100 transition-opacity duration-300 starting:opacity-0">
Появляюсь плавно
</div>
@starting-style зависит от браузера. Для критичной анимации
предусмотрите запасной вариант.Уважайте настройку «уменьшить движение»
Часть людей отключает анимации из-за вестибулярных нарушений — для них
движение вызывает физическое недомогание. Система сообщает об этом через
prefers-reduced-motion, а Tailwind даёт варианты
motion-safe: и motion-reduce:.
<!-- анимация только для тех, кто её не отключал -->
<div class="motion-safe:animate-bounce">↓</div>
<!-- или наоборот: выключить движение для тех, кто просил -->
<div class="animate-pulse motion-reduce:animate-none">…</div>
Производительность
- Дёшево:
transform,opacity— обрабатывает видеокарта, раскладка не пересчитывается. - Дорого:
width,height,top,margin— каждый кадр браузер пересчитывает раскладку. will-change-transform— подсказка браузеру; ставьте её точечно и не оставляйте навсегда.
<!-- ❌ дёргается: анимируется ширина -->
<div class="w-32 transition-all hover:w-64">…</div>
<!-- ✅ плавно: анимируется масштаб -->
<div class="w-32 transition-transform hover:scale-x-150 origin-left">…</div>