Урок 14. Домашнее задание: оживить проект

📁 Раздел: Состояния и темы ⏱️ Время изучения: ~45 мин 🎯 Сложность: Средняя

⚡ Кратко

Добавить движение в проект курса: состояния кнопок, скелетоны загрузки, появление уведомлений и одну собственную анимацию — с учётом prefers-reduced-motion.

Задание

  • все кнопки проекта получают transition-colors и active:scale-95;
  • карточки списка слегка приподнимаются при наведении;
  • страница со списком показывает скелетоны, пока «данные не загрузились»;
  • уведомление появляется собственной анимацией из @theme;
  • все анимации выключаются при prefers-reduced-motion.

Подготовка окружения

cd tailwind-course
npm run dev

Пошаговое решение

Шаг 1. Кнопки

Добавьте transition-colors duration-150 и active:scale-95. Проверьте, что фокус по-прежнему виден и не анимируется — контур должен появляться мгновенно.

Шаг 2. Карточки

transition-all duration-200 hover:-translate-y-1 hover:shadow-lg. На сенсорных устройствах эффект не сработает — это нормально, ничего важного за ним быть не должно.

Шаг 3. Скелетоны

Сделайте компонент-заглушку, повторяющий геометрию карточки. Показывайте его по флагу isLoading — данные пока можно имитировать таймером.

Шаг 4. Своя анимация

📄 src/index.css
/* 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); }
}

Примените motion-safe:animate-fade-up к уведомлению.

Как проверить

  • Ни одна анимация не длится дольше 300 мс.
  • При включённой настройке «уменьшить движение» интерфейс статичен.
  • Скелетон совпадает по размерам с реальной карточкой — контент не «прыгает».
  • В DevTools на вкладке Performance при наведении нет всплесков пересчёта раскладки.

Ориентир

<div class="max-w-md space-y-4">
  <a href="#" class="group block rounded-xl border border-slate-200 bg-white p-4 transition-all duration-200 hover:-translate-y-1 hover:shadow-lg">
    <div class="flex items-center justify-between">
      <h3 class="text-sm font-semibold text-slate-900">Отчёт по продажам</h3>
      <span class="text-slate-300 transition-transform group-hover:translate-x-1 group-hover:text-slate-500">→</span>
    </div>
    <p class="mt-1 text-sm text-slate-600">Наведите: карточка приподнимается.</p>
  </a>
  <div class="rounded-xl border border-slate-200 p-4">
    <div class="h-3 w-1/2 animate-pulse rounded bg-slate-200"></div>
    <div class="mt-2 h-3 animate-pulse rounded bg-slate-200"></div>
  </div>
  <div class="animate-fade-up rounded-lg border border-emerald-200 bg-emerald-50 p-3">
    <p class="text-sm text-emerald-900">Уведомление с анимацией появления</p>
  </div>
</div>