Legan Studio
Все статьи
~ 5 мин чтения

Tailwind в большом проекте: best practices

Как структурировать Tailwind в проекте на сотни компонентов — токены, темы, повторное использование, организация классов и борьба с шумом разметки.

  • сайт
  • разработка
  • стек

Tailwind отлично работает на маленьких проектах. На больших — без правил быстро превращается в кашу из 25 классов на каждом div. Расскажу, как мы держим Tailwind в порядке на проектах в 200+ компонентов.

Дизайн-токены через CSS-переменные

Не пишите цвета напрямую (bg-blue-500, text-gray-900). Вынесите в CSS-переменные через Tailwind config:

theme: {
  extend: {
    colors: {
      bg: "var(--bg)",
      fg: "var(--fg)",
      primary: "var(--primary)",
      "primary-fg": "var(--primary-fg)",
    }
  }
}

В globals.css объявляете --bg, --fg, --primary для светлой темы. Это даёт два преимущества: легко менять палитру централизованно, и поддержка тем (если когда-нибудь понадобятся).

Радиусы, тени, шрифтовые шкалы — туда же. Стандартные rounded-lg заменяются на rounded-[var(--radius)] или семантические rounded-card.

cn() и tailwind-merge

clsx плюс tailwind-merge — must have. Создаёте утилиту cn():

import { twMerge } from "tailwind-merge";
import { clsx } from "clsx";

export function cn(...inputs) {
  return twMerge(clsx(inputs));
}

Используете везде, где нужно условно склеить классы:

<div className={cn("p-4", isActive && "bg-primary", className)} />

tailwind-merge решает конфликты: если в дефолтных классах был p-4, а пробросили p-6 — он уберёт первый. Без этого — классы накладываются непредсказуемо.

Компоненты вместо длинных классов

Если у вас в коде 5 раз повторяется flex items-center justify-between gap-3 px-4 py-2 rounded-md border border-border bg-bg-card hover:bg-bg-subtle transition-colors — это компонент Card, а не разметка.

shadcn/ui или собственная библиотека UI-компонентов — основа. Уровни абстракции: примитивы (Button, Input, Card), составные (Form, Modal, Sidebar), фичи (ProductCard, OrderSummary).

@apply: использовать или нет

Спорный вопрос. Tailwind официально не рекомендует @apply для всего, но в реальных проектах он удобен для трёх случаев:

  1. Утилиты, которые часто повторяются (.card, .section-padding) — в @layer components.
  2. Стилизация сторонних компонентов, к которым нет прямого доступа.
  3. Адаптация классов из дизайн-системы под маркетинговые секции.

Не злоупотребляйте: @apply всё равно компилируется в обычный CSS, и преимущества Tailwind (atomic CSS, минимальный размер) теряются.

Сортировка классов

prettier-plugin-tailwindcss — подключите. Он сортирует классы в едином порядке (layout → spacing → sizing → typography → colors → effects). Code review становится проще, конфликтов меньше.

Без сортировки порядок классов внутри строк хаотичен, и cn("p-4 bg-red", className) ведёт себя по-разному при разных порядках.

Темы и режимы

Если нужны темы — делайте через CSS-переменные плюс data-theme:

[data-theme="dark"] {
  --bg: 18 18 22;
  --fg: 240 240 240;
}

Не используйте Tailwind dark: префикс на всех компонентах — это усложняет разметку и фиксирует дуальность. С CSS-переменными можно поддержать сколько угодно тем без изменений в компонентах.

Производительность сборки

Tailwind v3+ компилирует только используемые классы. На проекте 200 компонентов финальный CSS обычно 30-80 КБ (gzipped: 8-15 КБ). Это нормально.

Что замедляет сборку: широкие шаблоны в content (например, **/*.tsx в monorepo с тысячами файлов). Указывайте конкретные пути. Используйте Tailwind v4 с новым движком — он быстрее v3 в 2-5 раз на больших проектах.

Линтинг и ESLint

Подключите eslint-plugin-tailwindcss. Он ловит несуществующие классы, неправильные модификаторы, неиспользуемые negative-классы. Это не критично, но снимает класс ошибок.

Также полезно правило, ограничивающее количество классов на одном элементе. Если на div больше 15 классов — это сигнал к рефакторингу в компонент.

Итого

Tailwind на большом проекте — это дизайн-токены через CSS-переменные, cn-утилита с tailwind-merge, компонентная архитектура и автоматизация сортировки. Без этого через год Tailwind становится главным антипаттерном проекта. С этим — основа быстрой и поддерживаемой разработки.

Частые вопросы

Как организовать дизайн-токены в Tailwind?

Не пишите цвета напрямую (bg-blue-500, text-gray-900). Вынесите в CSS-переменные через Tailwind config: theme.extend.colors с bg: "var(--bg)", primary: "var(--primary)" и т.д. В globals.css объявляете --bg, --fg, --primary для светлой темы. Это даёт два преимущества: легко менять палитру централизованно, и поддержка тем (если когда-нибудь понадобятся). Радиусы, тени, шрифтовые шкалы — туда же. Стандартные rounded-lg заменяются на rounded-[var(--radius)] или семантические rounded-card.

Зачем нужна утилита cn() с tailwind-merge?

clsx плюс tailwind-merge — must have. Создаёте утилиту cn(), используете везде, где нужно условно склеить классы. tailwind-merge решает конфликты: если в дефолтных классах был p-4, а пробросили p-6 — он уберёт первый. Без этого классы накладываются непредсказуемо. Это особенно важно при работе с переиспользуемыми компонентами, которые принимают className пропсом — без cn() пользователь компонента не сможет переопределить стили предсказуемо.

Когда выносить Tailwind-классы в компонент?

Если у вас в коде 5 раз повторяется flex items-center justify-between gap-3 px-4 py-2 rounded-md border border-border bg-bg-card hover:bg-bg-subtle transition-colors — это компонент Card, а не разметка. shadcn/ui или собственная библиотека UI-компонентов — основа. Уровни абстракции: примитивы (Button, Input, Card), составные (Form, Modal, Sidebar), фичи (ProductCard, OrderSummary). Когда на div больше 15 классов — это сигнал к рефакторингу в компонент.

Стоит ли использовать @apply в Tailwind?

Спорный вопрос. Tailwind официально не рекомендует @apply для всего, но в реальных проектах он удобен для трёх случаев. Утилиты, которые часто повторяются (.card, .section-padding) — в @layer components. Стилизация сторонних компонентов, к которым нет прямого доступа. Адаптация классов из дизайн-системы под маркетинговые секции. Не злоупотребляйте: @apply всё равно компилируется в обычный CSS, и преимущества Tailwind (atomic CSS, минимальный размер) теряются. Используйте точечно.

Как реализовать темы (светлая/тёмная) на Tailwind?

Через CSS-переменные плюс data-theme. В CSS объявляете [data-theme="dark"] { --bg: 18 18 22; --fg: 240 240 240; }. Не используйте Tailwind dark: префикс на всех компонентах — это усложняет разметку и фиксирует дуальность. С CSS-переменными можно поддержать сколько угодно тем без изменений в компонентах. Просто переопределяете переменные в data-theme, и весь UI автоматически перерисовывается. Это удобнее для масштабирования и для добавления новых тем.

Что важно знать о производительности Tailwind в больших проектах?

Tailwind v3+ компилирует только используемые классы. На проекте 200 компонентов финальный CSS обычно 30-80 КБ (gzipped: 8-15 КБ). Это нормально. Что замедляет сборку: широкие шаблоны в content (например, **/*.tsx в monorepo с тысячами файлов). Указывайте конкретные пути. Используйте Tailwind v4 с новым движком — он быстрее v3 в 2-5 раз на больших проектах. Подключите prettier-plugin-tailwindcss для автоматической сортировки классов и eslint-plugin-tailwindcss для линтинга.