Tailwind CSS — утилитарная стилизация сайтов

Tailwind CSS — это utility-first фреймворк: вместо готовых компонентов ты собираешь стили из маленьких классов-утилит прямо в разметке. В этом уроке ты научишься подключать Tailwind, настраивать его, строить адаптивные сетки и подключать тёмную тему — без единой строчки обычного CSS.

Уровень: начальный 17 разделов 3–4 часа

1. Что такое Tailwind CSS и utility-first

Классический CSS ты пишешь в отдельном файле и придумываешь имена классов. Tailwind работает иначе: в браузер попадает готовый набор мелких утилит — p-4, flex, text-center, — и ты просто комбинируешь их в HTML. Никто не мешает обоим подходам сосуществовать, но Tailwind меняет то, как ты мыслишь о вёрстке.

<!-- Обычный CSS -->
<button class="btn-primary">Войти</button>

/* в файле style.css */
.btn-primary {
  background: #2563eb;
  padding: 10px 20px;
  border-radius: 8px;
  color: #fff;
}

<!-- Tailwind CSS -->
<button class="bg-blue-600 px-5 py-2.5 rounded-lg text-white">Войти</button>
Стили живут рядом с разметкой, поэтому уже не бывает «забыл, какой класс что делает». Плюс не нужно выдумывать сотни имён для мелких элементов.

2. Установка: CDN и npm

Для экспериментов проще всего подключить Play CDN одним тегом script. Так можно проверять утилиты в браузере без сборки.

<head>
  <!-- Play CDN: только для прототипов, не для продакшена -->
  <script src="https://cdn.tailwindcss.com"></script>
</head>

Для настоящего проекта Tailwind ставят через npm и подключают к сборщику. Например, с Vite:

npm install tailwindcss @tailwindcss/vite

// Vite: в конфиге (vite.config.js)
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [tailwindcss()]
})
CDN удобен для обучения и демо, но не годится для продакшена: он приносит почти весь Tailwind в браузер. При установке через npm сборщик вырезает только те классы, что реально встретились в твоих файлах.

3. Настройка через tailwind.config

В Tailwind 4 конфигурация задаётся CSS-директивой @theme, а в версии 3 — файлом tailwind.config.js. Секция content обязательно должна перечислять файлы, в которых Tailwind ищет классы.

// tailwind.config.js (Tailwind 3)
module.exports = {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx,vue}'],
  theme: {
    extend: {
      colors: {
        brand: {
          light: '#60a5fa',
          DEFAULT: '#2563eb',
          dark: '#1e40af'
        }
      },
      fontFamily: {
        sans: ['Inter', 'sans-serif']
      }
    }
  },
  darkMode: 'class'
}
Если забыть путь в content, Tailwind просто не увидит твои классы, и кнопки останутся без стилей. Частая ошибка новичков — пропустить новую папку из сканирования.

4. Базовые утилиты: цвет и типографика

Около 90% повседневной вёрстки — это несколько десятков утилит для текста и фона. Значения шагов (50, 100, ..., 900) задают оттенок цвета: чем больше число, тем темнее.

<p class="text-blue-700 font-semibold text-lg leading-snug tracking-tight">
  Привет, мир!
</p>

<div class="bg-gray-100 text-gray-900 rounded-md">Карточка</div>

<span class="bg-emerald-100 text-emerald-800 px-2 py-0.5 rounded-full text-sm">
  В наличии
</span>
КатегорияПримеры классовЧто делает
цвет текстаtext-blue-600, text-gray-500задаёт цвет шрифта
цвет фонаbg-blue-600, bg-whiteзадаёт фон
размер шрифтаtext-sm, text-lg, text-4xlуправляет font-size
жирностьfont-normal, font-boldуправляет font-weight
межстрочныйleading-5, leading-relaxedуправляет line-height
регистрuppercase, lowercaseпреобразует текст
Комбинирование «цвет текста + цвет фона того же семейства» — приём для аккуратных бейджей и плашек: text-emerald-800 bg-emerald-100.

5. Отступы и пространство

За отступы отвечают три семейства: p-* (внутренние), m-* (внешние) и gap-* (между элементами flex/grid). Шкала продублирована по сторонам: px-4, py-4, ml-auto.

<!-- padding со всех сторон, по горизонтали/вертикали -->
<div class="p-6 px-4 py-8">...</div>

<!-- margin для разнесения блоков по краям -->
<nav class="flex justify-between items-center px-6">
  <a href="#">Логотип</a>
  <div class="flex gap-3">
    <a href="#" class="ml-auto">Каталог</a>
    <a href="#">Контакты</a>
  </div>
</nav>

<!-- центрирование блока фиксированной ширины -->
<div class="max-w-3xl mx-auto">Контент по центру</div>
Классы вида space-x-4 добавляют отступ между соседними детьми контейнера автоматически — удобно для списков ссылок без ручных ml-* на каждом пункте.

6. Flexbox и Grid на утилитах

Flex и Grid включаются двумя классами — flex и grid. Всё остальное — это их свойства в виде утилит: направление, выравнивание, количество колонок.

<!-- ряд кнопок справа -->
<div class="flex gap-2 justify-end items-center">
  <button class="px-4 py-2 rounded bg-gray-200">Отмена</button>
  <button class="px-4 py-2 rounded bg-blue-600 text-white">Сохранить</button>
</div>

<!-- сетка из трёх одинаковых карточек -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
  <div class="bg-white shadow rounded-lg p-6">Карточка 1</div>
  <div class="bg-white shadow rounded-lg p-6">Карточка 2</div>
  <div class="bg-white shadow rounded-lg p-6">Карточка 3</div>
</div>
ЗадачаКлассы
гибкий рядflex, flex-col, flex-wrap
выравнивание по главной осиjustify-start / center / between / end
выравнивание по поперечной осиitems-start / center / stretch
колонки сеткиgrid-cols-2, grid-cols-12
занять несколько колонокcol-span-2, col-span-4
расстояние между элементамиgap-4, gap-x-4, gap-y-6
Золотой рецепт сетки: grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3. На телефоне — одна колонка, на планшете — две, на десктопе — три. Это и есть адаптивность без медиазапросов.

7. Адаптивность через префиксы

Tailwind не заставляет писать медиазапросы: достаточно добавить префикс брейкпоинта. Утилита md: применится только на экранах от 768px и шире, а lg: — от 1024px.

<header class="flex flex-col md:flex-row justify-between p-6">
  <h1 class="text-2xl md:text-4xl">Заголовок сайта</h1>
  <nav class="flex flex-col md:flex-row gap-2 md:gap-6">
    <a href="#">Главная</a>
    <a href="#">Блог</a>
    <a href="#">Контакты</a>
  </nav>
</header>
ПрефиксМин. ширина экранаПример
sm:640pxsm:grid-cols-2
md:768pxmd:flex-row
lg:1024pxlg:grid-cols-3
xl:1280pxxl:max-w-5xl
2xl:1536px2xl:gap-10
Пиши сначала базовое состояние (мобильное), затем добавляй префиксные варианты. Если сделать наоборот, мобильная версия может «съесть» стили десктопа из-за порядка генерации классов.

8. Тёмная тема через dark:

Для тёмной темы в Tailwind есть встроенный вариант dark:. По умолчанию он реагирует на системную настройку браузера (media-запрос), а через darkMode: 'class' — на класс dark у корневого элемента. С классом легко сделать переключатель темы на сайте.

// tailwind.config.js
module.exports = {
  darkMode: 'class'
}

// script.js — переключение темы
document.documentElement.classList.toggle('dark')
<body class="bg-white text-gray-900 dark:bg-gray-900 dark:text-gray-100">
  <div class="max-w-xl mx-auto p-6 rounded-xl
              bg-gray-50 dark:bg-gray-800">
    <h1 class="text-xl font-bold">Карточка</h1>
    <p class="text-gray-600 dark:text-gray-300">
      Текст спокойно меняет цвет при переключении темы.
    </p>
  </div>
</body>
Держи тёмные стили кратко: обычно достаточно перекрасить фон, карточки, текст и границы. Не дублируй всю палитру на каждый элемент.

9. Состояния hover, focus и прочие варианты

Псевдоклассы включаются своими префиксами. Их можно комбинировать с брейкпоинтами и тёмной темой: md:hover:bg-blue-700 — «при наведении на экранах от 768px».

<button class="bg-blue-600 hover:bg-blue-700 active:bg-blue-800
               focus-visible:outline focus-visible:outline-2
               focus-visible:outline-blue-400 transition-colors
               px-5 py-2.5 rounded-lg text-white">
  Нажми меня
</button>

<a href="#" class="text-blue-600 hover:text-blue-800 visited:text-purple-600">
  Ссылка
</a>
ПрефиксКогда срабатывает
hover:при наведении курсора
focus:при фокусе через мышь или клавиатуру
focus-visible:фокус с клавиатуры (для доступности)
active:в момент клика
first:первый из однотипных элементов
checked:выбранный чекбокс или радио
group-hover:при наведении на родителя с классом group
Для появления карточки при наведении на контейнер используй group на родителе и group-hover:opacity-100 opacity-0 на скрытом элементе — без единой строчки JS.

10. @apply, кастомные утилиты и интеграция с React/Vue

Когда одни и те же связки классов встречаются по сто раз, хочется дать им имя. Директива @apply собирает утилиты в обычный класс в твоём CSS — это ещё и способ постепенно переезжать на Tailwind.

/* input.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

.btn-primary {
  @apply bg-blue-600 hover:bg-blue-700 text-white
         font-medium px-5 py-2.5 rounded-lg transition-colors;
}

В React и Vue тот же подход: утилиты передаются как строки классов, а условные модификаторы получаются из шаблонного синтаксиса.

// React
export default function Button({ primary, children }) {
  const cls = primary
    ? 'bg-blue-600 hover:bg-blue-700 text-white'
    : 'bg-gray-200 hover:bg-gray-300 text-gray-900'
  return (
    <button className={`px-5 py-2.5 rounded-lg transition-colors ${cls}`}>
      {children}
    </button>
  )
}

// Vue
<template>
  <button :class="[base, primary ? 'bg-blue-600' : 'bg-gray-200']">
    <slot />
  </button>
</template>
Не злоупотребляй @apply: смысл Tailwind в том, чтобы классы были маленькими и предсказуемыми. Компонент с десятками вложенных @apply превращается в обычный CSS-монолит, но с худшей читаемостью.

11. Плагины и кастомные варианты

Экосистема Tailwind расширяется плагинами: typography даёт красивые стили для статей, forms — аккуратные input и select. Установка плагина — пара команд и одна строка в конфиге.

// tailwind.config.js
import typography from '@tailwindcss/typography'
import forms from '@tailwindcss/forms'

export default {
  plugins: [typography, forms],
  theme: {
    extend: {
      colors: {
        brand: '#ff6b35'
      }
    }
  }
}

Свои утилиты добавляются функцией plugin(function ({ addUtilities }) { ... }) — это удобно для повторяющихся теней или градиентов.

Варианты вроде group-hover и peer-checked тоже расширяются через плагины: они дают состояния без JavaScript. Логика «наведения на родителя» перестаёт требовать отдельного скрипта — меньше строк, меньше шансов на ошибку.

<article class="prose prose-lg">
  <h1>Готовый стиль статьи</h1>
</article>
Плагин — это просто набор утилит. Прежде чем писать свой, проверь заранее существующие: реестр tailwindcss.com/plugins покрывает большинство задач.

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

Tailwind v4 не генерирует «весь CSS». В файл попадают только классы, встреченные в файлах, которые указаны в настройках. Чем точнее пути content — тем меньше итоговый бандл.

// tailwind.config.js — какие файлы сканировать
export default {
  content: [
    './index.html',
    './src/**/*.{vue,js,ts,jsx,tsx}'
  ]
}

Если класс встречается только в сгенерированном динамически виде (например, bg-${color}), Tailwind его не найдёт. Выход — safelist или фиксированные варианты в разметке.

Для крупных проектов есть интеграция с бандлерами: PostCSS-плагин подключается к Vite и Webpack одной строкой, а минификация убирает лишнее. Конфигурацию тем держите минимальной: неиспользуемые цвета и размеры не генерируются.

Не склеивай имена классов из переменных: bg-${color} не сработает, так как сборщик не подставляет выражения. Перечисли варианты целиком.
Проверяй итоговый CSS через DevTools (в браузере: вкладка Network → style.css): если класс пропал — он не найден в content, а не «сломан».

13. Типовые макеты на практике

Соберём каркас страницы: шапка, основная сетка карточек и футер — только утилитами, без единой строчки «ручного» CSS.

<header class="flex items-center justify-between px-6 py-4 border-b">
  <a href="/" class="text-lg font-bold">Logo</a>
  <nav class="flex gap-6 text-sm text-gray-600">
    <a href="/"><a>Главная</a>
  </nav>
</header>

<main class="grid gap-6 p-6 sm:grid-cols-2 lg:grid-cols-3">
  <article class="rounded-xl border p-4 shadow-sm">
    <h2 class="text-base font-semibold">Карточка</h2>
    <p class="mt-2 text-sm text-gray-500">Описание товара</p>
  </article>
</main>

Такой подход держит вёрстку единообразной: одинаковые отступы, шрифты и сетки без дублирования. При этом каждый блок легко вывернуть через БЭМ-класс при необходимости.

Для реальных проектов этого каркаса достаточно: шапку можно вынести в компонент, карточки — переиспользовать, а адаптив менять одной-двумя утилитами. Когда макет вырастет, добавьте модалки и навигацию сверху сетки — Tailwind не ограничит в масштабе.

Правило «составных сеток»: grid определяет ряды, flex — то, что внутри ряда. Смешивать их в одном контейнере не стоит.

14. Tailwind вместе с Sass или PostCSS

Tailwind не отменяет препроцессоры: во многих проектах он работает «поверх». Sass даёт вложенность и миксины для повторяющихся кусков, а Tailwind — точечные утилиты для внешнего вида.

// app.scss — порядок подключения важен
@use "tailwindcss/base";
@use "tailwindcss/components";
@use "tailwindcss/utilities";

.card {
  background: var(--brand);   // CSS-переменная из @theme
  &:hover { transform: translateY(-2px); }
}

Подключай Tailwind-директивы до своих стилей, чтобы каскад не перекрывал утилиты. Миксины Sass удобны для «составных» компонентов, которые повторяются с параметрами.

CSS-переменные — мост между Tailwind и остальным кодом: определи их в @theme и используй в произвольном CSS без дублирования.
Не заворачивай @apply внутрь глубоко вложенных селекторов Sass без необходимости: вложенность усложняет чтение и тормозит сборку на больших проектах.
PostCSS-порядок критичен: если ты не видишь утилит, проверь, что плагины tailwind и autoprefixer идут в правильном порядке.

15. Адаптивность и доступность на утилитах

Адаптивность в Tailwind — это префиксы брейкпоинтов, но есть тонкости, которые пропускают: не только ширина, но и область касания, размер шрифта и порядок контента.

<!-- Кнопка с доступностью из коробки -->
<button class="min-h-11 px-4 rounded-lg
               focus-visible:outline-2 outline-blue-600
               motion-safe:transition-colors">
  Купить
</button>

Проверяй адаптив не только в DevTools, но и на реальных устройствах: браузер эмулирует ширину, но не тач-зоны и реальный рендеринг.

Собери чек-лист «обязательных» утилит доступности (outline, min-h, контраст) и прогоняй его по каждой новой кнопке.
Не игнорируй контраст: text-gray-400 на белом неприемлем для основного текста. Проверяй контраст в Lighthouse.

16. Шрифты и иконки рядом с Tailwind

Типографика и иконки — половина «дорогого вида». Tailwind не включает шрифты и иконки, но отлично с ними дружит через переменные и CSS-классы.

// tailwind.config.js
export default {
  theme: {
    fontFamily: {
      sans: ['Inter', 'system-ui', 'sans-serif'],
      mono: ['JetBrains Mono', 'ui-monospace']
    }
  }
}

Шрифты подключай локально (fontsource) или самодостаточным @font-face: внешние CDN потянут иконки и задержат первую отрисовку текста. Иконки — инлайновые SVG-компоненты, а не картинки: их можно красить через fill-current и масштабировать w-* h-*.

// React-компонент иконки
export const IconStar = ({ className }) => (
  <svg className={`w-5 h-5 fill-current ${className}`} viewBox="0 0 24 24">
    <path d="M12 2l3 6 7 1-5 5 1 7-6-3-6 3 1-7-5-5 7-1z" />
  </svg>
)

Иконка наследует цвет текста через currentColor и подстраивается под тёмную тему без дублирования кода.

Добавляй aria-hidden="true" декоративным иконкам — скринридеры не должны озвучивать «звезду» посреди кнопки.
Держи набор иконок в отдельных файлах и импортируй по месту; целые иконкопки подключай только для прототипов.

17. Частые ошибки верстальщика на Tailwind

Tailwind упрощает вёрстку, но даёт новичкам набор типовых ловушек. Пройдись по списку перед сдачей макета.

// Ошибка: динамический класс не сгенерируется
<div className={`bg-${status}-500`}>...</div>

// Выход: явный словарь
const colors = { ok: 'bg-green-500', error: 'bg-red-500' }
<div className={colors[status]}>...</div>

Если класс не применился — ищи «свой» конфликт в DevTools: посмотри computed styles и порядок правила. Чаще всего это дубликат утилиты или пропущенный путь в content.

Проверяй версию Tailwind: в v4 конфигурация задаётся CSS-директивами, а в v3 — файлом; гайды в интернете могут относиться к другой мажорной версии.
Не расширяй палитру «на каждый чих»: неиспользуемые цвета мутят дизайн-систему и растят бандл. Начинай с базовой палитры и расширяй осознанно.

18. Tailwind v4: CSS-first конфигурация

В v4 конфигурация уезжает из tailwind.config.js в CSS: кастомные токены объявляются директивами @theme, и из них автоматически рождаются утилиты. Меньше JS-обработки, быстрее сборка, а дизайн-система читается прямо в стилях.

@import "tailwindcss";

@theme {
  --color-brand: #7c3aed;
  --font-display: "Inter", sans-serif;
}

Переменная --color-brand создаст классы bg-brand, text-brand, border-brand — так токены связываются с утилитами без ручного расширения конфига.

Гайды 2022–2023 годов описывают v3: команды установки и синтаксис конфига отличаются. Сверяйте версию по документации v4.
Держите токены бренда в одном месте: дизайнер меняет два цвета — и весь сайт обновляется.

19. UI-кит: Storybook и документация компонентов

Утилиты — быстрые, но «сырые»: в команде их оборачивают в компоненты (кнопки, карточки, поля), а для разработки и ревью заводится витрина — Storybook. Каждый компонент получает «историю» с разными состояниями.

// Button.stories.tsx
export const Primary = {
  args: {
    label: "Купить",
    variant: "primary",
  },
};

Результат: дизайнер проверяет «живые» компоненты, разработчик видит все состояния, а бота/скриншот-тесты (chromatic) ловят регрессии после правки токенов.

Правило «одна история на состояние»: loading, error, empty, hover — каждое начинает жить до интеграции на страницу.
Синергия с Tailwind: Storybook рисует компонент изолированно, утилиты же собираются тем же пайплайном PostCSS — стили «из коробки» как в проде.

20. Дизайн-токены: подключение бренда

Дизайн-токены — именованные атомы стиля: цвет, типографика, отступы, радиусы. В Tailwind v4 они превращаются в CSS-переменные (раздел 18), и все утилиты начинают говорить на языке бренда, а не на «дефолтном сером».

@theme {
  --color-primary: #0f766e;
  --color-accent: #f59e0b;
  --spacing-section: 6rem;
  --radius-card: 1rem;
}

Связь с дизайнерами: спросите у них токены (Figma Variables) и перенесите в @theme построчно — расхождений между макетом и кодом станет заметно меньше.

Не заводите токены «на каждый чих»: пара сотен атомов — это норма, а двадцать «почти одинаковых синих» — тупик, в котором рождаются расхождения.
Называйте токены по роли (color-brand, text-muted), а не по внешнему виду — тогда смена дизайна не переписывает код.

21. Tailwind против BEM, CSS Modules и CSS-in-JS

Tailwind — не единственный подход к стилям, и вопрос «что выбрать» решается контекстом. Сравнение с ближайшими конкурентами помогает принимать это решение осознанно.

ПодходСильная сторонаЦена
Tailwind (utility-first)скорость, консистентность, средний опыт командыдлинная разметка классов
BEMсемантика «блок-элемент-модификатор», старый кодмного ручного именования
CSS Modulesизоляция стилей и scoped-классыменьше переиспользования тем
CSS-in-JS (styled)типы и логика рядом с стилямиruntime-затраты, бандл

Правило выбора: для прототипов и продуктовых команд Tailwind даёт самый короткий путь; для дизайн-систем с жёсткой разметкой может подойти BEM, а для микрофронтендов — CSS Modules из-за изоляции.

Никто не запрещает микс: например, Tailwind для быстрых слоёв и BEM для «вечных» публичных компонентов библиотеки.
Обратите внимание: CSS-in-JS в рантайме платит производительностью. В крупном SSR-проекте этот фактор заметен сильнее «удобства» синтаксиса.

Что дальше

Ты прошёл весь путь: от понимания utility-first и установки до адаптивных сеток, тёмной темы и интеграции с фреймворками. Закрепи навык, сверстав карточку товара с сеткой карточек и переключателем темы на чистом Tailwind. Отличным продолжением будет изучение Bootstrap для сравнения подходов, а также курс по Vue 3 или React, чтобы соединить Tailwind с реальным интерфейсом.

← Вернуться к курсам