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

19. Best Practices

Иллюстрация к уроку

Tailwind даёт свободу, но без дисциплины код быстро превращается в кашу. Вот проверенные практики, которые сохранят проект чистым и поддерживаемым.

Без сортировки классы — хаос. С сортировкой — логичная структура:

Окно терминала
npm install -D prettier prettier-plugin-tailwindcss
prettier.config.js
module.exports = {
plugins: ['prettier-plugin-tailwindcss'],
}

До:

<div class="text-white p-4 bg-blue-600 rounded-lg flex hover:bg-blue-700 mb-4 items-center gap-2">

После (автосортировка):

<div class="mb-4 flex items-center gap-2 rounded-lg bg-blue-600 p-4 text-white hover:bg-blue-700">

Порядок сортировки Prettier: layout → flex/grid → spacing → sizing → typography → background → border → effects → transitions → responsive → states.

Плохо — @apply для всего:

/* ❌ Не делай так */
.card-title { @apply text-xl font-bold text-gray-900 mb-2; }
.card-text { @apply text-sm text-gray-500 leading-relaxed; }
.card-wrapper { @apply bg-white rounded-2xl p-6 shadow-sm; }

Хорошо — React компонент:

// ✅ Компонент вместо @apply
function Card({ title, children }) {
return (
<div className="rounded-2xl bg-white p-6 shadow-sm">
<h3 className="mb-2 text-xl font-bold text-gray-900">{title}</h3>
<p className="text-sm leading-relaxed text-gray-500">{children}</p>
</div>
)
}

Используй фиксированный набор значений — не разбрасывай рандомные отступы:

<!-- ❌ Хаос -->
<div class="p-3 mb-5 mt-7 gap-3.5">Разные значения повсюду</div>
<!-- ✅ Система -->
<!-- Маленький: 2 (8px) -->
<!-- Средний: 4 (16px) -->
<!-- Большой: 6 (24px) -->
<!-- Огромный: 8-12 (32-48px) -->
<div class="p-4 mb-6 mt-8 gap-4">Консистентная система</div>

Всегда начинай с мобильной версии:

<!-- ❌ Неправильно — Desktop-first -->
<div class="grid grid-cols-3 md:grid-cols-2 sm:grid-cols-1">
<!-- ✅ Правильно — Mobile-first -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">

Не привязывайся к конкретным цветам — используй семантические имена:

// ❌ Конкретные цвета
colors: { blue: {...}, red: {...} }
// ✅ Семантические
colors: {
primary: 'hsl(var(--primary))',
destructive: 'hsl(var(--destructive))',
muted: 'hsl(var(--muted))',
background: 'hsl(var(--background))',
}
<!-- ❌ Привязка к цвету -->
<button class="bg-blue-600 hover:bg-blue-700">
<!-- ✅ Семантика — легко поменять тему -->
<button class="bg-primary hover:bg-primary/90">
src/
├── components/
│ ├── ui/ ← shadcn/ui или свои базовые компоненты
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ └── input.tsx
│ ├── Header.tsx ← бизнес-компоненты
│ └── Sidebar.tsx
├── lib/
│ └── utils.ts ← cn() функция
├── styles/
│ └── globals.css ← @tailwind директивы + CSS variables
└── tailwind.config.ts
<!-- ❌ Не смешивай Tailwind и inline styles -->
<div class="rounded-lg" style="padding: 20px; background: #333;">
<!-- ✅ Всё через Tailwind -->
<div class="rounded-lg p-5 bg-gray-800">
<!-- ✅ Или arbitrary values для нестандартных значений -->
<div class="rounded-lg p-[20px] bg-[#333]">

Для длинных списков классов группируй логически:

// Читаемость через форматирование
<div
className={cn(
// Layout
'flex items-center justify-between',
// Spacing
'px-6 py-4',
// Visual
'rounded-xl bg-white shadow-sm',
// Border
'border border-gray-200',
// States
'hover:shadow-md transition-shadow',
// Responsive
'md:px-8',
)}
>
<!-- ❌ Слишком много dark: классов -->
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100
border-gray-200 dark:border-gray-700 shadow-sm dark:shadow-gray-900/50">
<!-- ✅ Используй CSS переменные для dark mode -->
<div class="bg-background text-foreground border-border shadow-sm">
// lib/utils.ts — стандарт для любого проекта с Tailwind
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}