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

Tailwind CSS

Разработчику

Tailwind CSS

Основы

Tailwind CSSCSS-фреймворк в стиле utility-first ("сначала утилиты"). Внешний вид задают готовыми классами в атрибуте class HTML-элемента, а не отдельным правилом .card { padding: 1rem } в файле стилей.

<button class="rounded-lg bg-blue-600 px-4 py-2 text-white hover:bg-blue-700">
Сохранить
</button>

Класс px-4 задаёт горизонтальный padding, bg-blue-600 — цвет фона, hover:bg-blue-700 — фон при наведении. Под капотом это обычные CSS-свойства — те же, что вы изучаете в блочной модели и Flex/Grid.

Tailwind сокращает запись знакомых свойств. Он не заменяет понимание каскада, адаптива и доступности.

Документация — tailwindcss.com. Справочник CSS на MDN — MDN: CSS.


Плюсы и минусы

Плюсы

  • быстрый прототип кнопки, карточки или сетки без переключения между HTML- и CSS-файлами
  • единая шкала отступов и цветов (p-4, gray-500) вместо случайных пикселей
  • адаптив через префиксы sm:, md:, lg: в духе mobile-first
  • состояния hover:, focus:, dark: рядом с базовым классом
  • тема в tailwind.config для продакшена

Минусы

  • длинная строка class без переносов плохо читается
  • в продакшене нужна сборка, которая оставляет только использованные классы (purge / tree-shaking)
  • без базы CSS сложнее отлаживать в DevTools

Подключение для учёбы (CDN)

На статической странице и в лаборатории достаточно Play CDN — без Node.js:

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-slate-100 p-8">
<h1 class="text-2xl font-bold text-slate-800">Заметки</h1>
</body>
</html>

Рекомендуемый порядок практики:

  1. HTML-страницы целиком — каркас и теги
  2. HTML + CSS — макеты — те же задачи на чистом CSS
  3. Tailwind — готовые блоки — разбор каждого класса

В продакшене CDN не используют — подключают tailwindcss через npm/Vite и собирают только нужные классы. Подробнее — подключение CSS.


Как читать классы

Класс TailwindCSS-смысл
flex, griddisplay: flex / grid
items-center, justify-betweenвыравнивание во Flex
gap-4gap: 1rem (шкала Tailwind)
w-full, max-w-mdширина
text-sm, font-semiboldразмер и начертание шрифта
rounded-lg, shadow-mdскругление и тень
md:grid-cols-3с ширины 768px — три колонки grid

Префикс dark: включает стили при тёмной теме — см. раздел про dark mode ниже и доступность и темы.


Полный макет страницы

Пример landing-страницы с шапкой, hero, сеткой карточек и подвалом. Разметка осмысленная — те же блоки, что в лаборатории HTML-страниц, но стили через утилиты:

<!DOCTYPE html>
<html lang="ru" class="h-full">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Курс по данным — IT Universe</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-full flex flex-col bg-slate-50 text-slate-900 antialiased">

<!-- Шапка -->
<header class="sticky top-0 z-10 border-b border-slate-200 bg-white/80 backdrop-blur">
<div class="mx-auto flex max-w-6xl items-center justify-between px-4 py-4">
<a href="/" class="text-lg font-bold text-indigo-600">IT Universe</a>
<nav class="hidden gap-6 text-sm font-medium md:flex">
<a href="#courses" class="hover:text-indigo-600">Курсы</a>
<a href="#about" class="hover:text-indigo-600">О проекте</a>
<a href="#contact" class="hover:text-indigo-600">Контакты</a>
</nav>
<button type="button"
class="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white
hover:bg-indigo-700 focus-visible:outline focus-visible:outline-2
focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
Войти
</button>
</div>
</header>

<!-- Hero -->
<main class="flex-1">
<section class="mx-auto max-w-6xl px-4 py-16 md:py-24">
<div class="grid items-center gap-12 md:grid-cols-2">
<div>
<p class="text-sm font-semibold uppercase tracking-wide text-indigo-600">
Бесплатная энциклопедия
</p>
<h1 class="mt-2 text-4xl font-extrabold tracking-tight md:text-5xl">
От HTML до Big Data — одной дорожной картой
</h1>
<p class="mt-4 text-lg text-slate-600">
Статьи, лаборатории и практикумы для разработчиков и аналитиков.
</p>
<div class="mt-8 flex flex-wrap gap-4">
<a href="#courses"
class="rounded-lg bg-indigo-600 px-6 py-3 font-semibold text-white shadow
hover:bg-indigo-700">
Начать учиться
</a>
<a href="/lab/Примеры/1117"
class="rounded-lg border border-slate-300 bg-white px-6 py-3 font-semibold
hover:bg-slate-50">
Tailwind в Lab
</a>
</div>
</div>
<div class="rounded-2xl bg-gradient-to-br from-indigo-500 to-violet-600 p-8 text-white shadow-xl">
<p class="text-sm opacity-90">Следующий шаг</p>
<p class="mt-2 text-2xl font-bold">CSS Flex и Grid</p>
<p class="mt-4 opacity-90">После этой главы — готовые блоки в лаборатории 1117.</p>
</div>
</div>
</section>

<!-- Карточки курсов -->
<section id="courses" class="border-t border-slate-200 bg-white py-16">
<div class="mx-auto max-w-6xl px-4">
<h2 class="text-2xl font-bold">Разделы энциклопедии</h2>
<div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
<article class="rounded-xl border border-slate-200 p-6 shadow-sm hover:shadow-md transition-shadow">
<h3 class="font-semibold text-indigo-600">HTML и разметка</h3>
<p class="mt-2 text-sm text-slate-600">Теги, формы, доступность, Web Components.</p>
</article>
<article class="rounded-xl border border-slate-200 p-6 shadow-sm hover:shadow-md transition-shadow">
<h3 class="font-semibold text-indigo-600">CSS и Tailwind</h3>
<p class="mt-2 text-sm text-slate-600">Utility-first, адаптив, тёмная тема.</p>
</article>
<article class="rounded-xl border border-slate-600 bg-slate-900 p-6 text-white shadow-sm">
<h3 class="font-semibold">Данные и SQL</h3>
<p class="mt-2 text-sm text-slate-300">CSV, Parquet, запросы, визуализация.</p>
</article>
</div>
</div>
</section>
</main>

<!-- Подвал -->
<footer id="contact" class="border-t border-slate-200 bg-slate-100 py-8">
<div class="mx-auto flex max-w-6xl flex-col items-center justify-between gap-4 px-4
text-sm text-slate-600 md:flex-row">
<p>© 2026 IT Universe</p>
<p>Сравните этот макет с версией на чистом CSS — <a href="/lab/Примеры/110" class="text-indigo-600 underline">Lab 110</a>.</p>
</div>
</footer>

</body>
</html>

Паттерны в макете:

  • min-h-full flex flex-col — страница на всю высоту, подвал прижат вниз
  • sticky top-0 — шапка при прокрутке
  • max-w-6xl mx-auto px-4 — контентная колонка по центру
  • md:grid-cols-2 — двухколоночный hero с планшета
  • focus-visible:outline — видимый фокус для клавиатуры (a11y)

Адаптивные паттерны

Tailwind следует mobile-first: без префикса — стиль для всех экранов; с префиксом — от breakpoint и выше.

Префиксmin-widthТипичное устройство
sm:640pxбольшой телефон
md:768pxпланшет
lg:1024pxноутбук
xl:1280pxширокий монитор
2xl:1536pxultra-wide

Скрыть на мобиле, показать на десктопе

<nav class="hidden md:flex md:gap-6">...</nav>
<button class="md:hidden" aria-label="Меню"></button>

Стек → сетка

<div class="flex flex-col gap-4 md:flex-row md:items-center">
<img class="w-full md:w-1/3" src="photo.jpg" alt="">
<p class="flex-1">Текст рядом с фото на широком экране.</p>
</div>

Responsive typography

<h1 class="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold">
Заголовок растёт с экраном
</h1>

Container queries (Tailwind v4+) — стили от размера родителя, не viewport. Пока в учебных проектах чаще достаточно md: / lg:.

Подробнее о медиазапросах вручную — адаптивность.


Design tokens и tailwind.config

Design tokens — именованные значения дизайн-системы (цвет бренда, радиус, шрифт). В Tailwind они живут в tailwind.config.js (v3) или @theme (v4).

Пример расширения темы для продакшен-проекта на Vite:

/** @type {import('tailwindcss').Config} */
export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx,vue}"],
darkMode: "class",
theme: {
extend: {
colors: {
brand: {
50: "#eef2ff",
100: "#e0e7ff",
500: "#6366f1",
600: "#4f46e5",
700: "#4338ca",
},
},
fontFamily: {
sans: ["Inter", "system-ui", "sans-serif"],
mono: ["JetBrains Mono", "monospace"],
},
borderRadius: {
card: "12px",
},
spacing: {
18: "4.5rem",
},
boxShadow: {
card: "0 4px 24px rgba(15, 23, 42, 0.08)",
},
},
},
plugins: [
require("@tailwindcss/forms"),
require("@tailwindcss/typography"),
],
};

Использование токенов в разметке:

<div class="rounded-card bg-brand-50 p-6 shadow-card font-sans">
<h2 class="text-brand-700">Карточка бренда</h2>
</div>

Не перезаписывайте всю шкалу colors без нужды — extend добавляет к дефолтной палитре slate, gray, indigo и т.д.

Согласование с CSS-переменными:

// tailwind.config — colors через var()
colors: {
surface: "rgb(var(--color-surface) / <alpha-value>)",
},
:root { --color-surface: 255 255 255; }
.dark { --color-surface: 15 23 42; }

@layer, @apply и компоненты

Когда одна и та же комбинация утилит повторяется десятки раз, её выносят в компонентный класс — но не произвольный .btn в глобальном CSS, а через @layer components внутри Tailwind:

/* src/styles/components.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
.btn-primary {
@apply rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white
hover:bg-indigo-700 focus-visible:outline focus-visible:outline-2
focus-visible:outline-offset-2 focus-visible:outline-indigo-600
disabled:cursor-not-allowed disabled:opacity-50;
}

.input-field {
@apply block w-full rounded-lg border border-slate-300 px-3 py-2 text-sm
shadow-sm placeholder:text-slate-400
focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20;
}

.card {
@apply rounded-xl border border-slate-200 bg-white p-6 shadow-sm;
}
}
<button class="btn-primary">Сохранить</button>
<input class="input-field" type="email" placeholder="you@example.com">

@layer base — сброс и базовые стили:

@layer base {
h1 { @apply text-3xl font-bold tracking-tight; }
a { @apply text-indigo-600 underline-offset-2 hover:underline; }
}

@layer utilities — свои одноразовые утилиты:

@layer utilities {
.text-balance { text-wrap: balance; }
}

Правила:

  • @apply работает только с известными классами Tailwind (не с произвольными значениями вроде top-[117px] во всех версиях)
  • не @apply всё подряд — длинные цепочки теряют смысл utility-first
  • в React/Vue чаще делают компонент <Button> с теми же классами в JSX — см. компоненты-рецепты

Тёмная тема (class и media)

Два режима в tailwind.config:

media (по умолчанию в старых версиях) — следует prefers-color-scheme ОС:

<div class="bg-white text-slate-900 dark:bg-slate-900 dark:text-slate-100">
Автоматически по системе
</div>

class — переключатель на странице:

// tailwind.config.js
export default { darkMode: "class" };
<html lang="ru" class="dark">
<body class="bg-white dark:bg-slate-950 text-slate-900 dark:text-slate-100">
// переключатель
document.documentElement.classList.toggle("dark");
localStorage.setItem("theme", document.documentElement.classList.contains("dark") ? "dark" : "light");

Комбинация обоих подходов — сначала прочитать localStorage, иначе matchMedia:

if (localStorage.theme === "dark" ||
(!("theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}

Семантические токены упрощают dark:

<div class="bg-surface text-foreground border-border">

где surface, foreground, border определены в config для light/dark через CSS variables.


Плагин @tailwindcss/forms

Формы по умолчанию выглядят по-разному в Chrome, Safari, Firefox. Плагин @tailwindcss/forms выравнивает базовый вид input, select, textarea, checkbox:

npm install -D @tailwindcss/forms
// tailwind.config.js
plugins: [require("@tailwindcss/forms")],
<form class="mx-auto max-w-md space-y-4">
<label class="block">
<span class="text-sm font-medium text-slate-700">Email</span>
<input type="email" class="mt-1 block w-full rounded-lg border-slate-300
focus:border-indigo-500 focus:ring-indigo-500" />
</label>
<label class="flex items-center gap-2">
<input type="checkbox" class="rounded border-slate-300 text-indigo-600 focus:ring-indigo-500" />
<span class="text-sm">Запомнить меня</span>
</label>
<button type="submit" class="btn-primary w-full">Войти</button>
</form>

Стратегия плагина strategy: "class" — стили только на элементах с классом form-input и т.д., если не хотите трогать все input на сайте.

Связь с HTML-формами и доступностью форм.


JIT, purge и размер CSS в продакшене

JIT (Just-In-Time, с Tailwind v3 — единственный режим) генерирует CSS только для классов, найденных в content. Старый purge — то же по смыслу.

Без сборки Play CDN тянет весь Tailwind (~3+ МБ) — для учёбы нормально, для prod — нет.

content в config должен покрывать все файлы с классами:

content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx,vue,svelte}",
"./components/**/*.php", // если SSR
],

Иначе класс из динамической строки не попадёт в CSS:

// Плохо — purge не видит
const color = "red";
el.className = `bg-${color}-500`;

// Хорошо — полные имена
const variants = { error: "bg-red-500", ok: "bg-green-500" };
el.className = variants[type];

Safelist для редких классов:

safelist: ["bg-red-500", "bg-green-500", "md:grid-cols-4"],

Production-сборка с Vite

Типичный стек — Vite + Tailwind v3/v4 + React или Vue.

npm create vite@latest my-app -- --template react
cd my-app
npm install -D tailwindcss postcss autoprefixer @tailwindcss/forms
npx tailwindcss init -p
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
// src/main.jsx
import "./index.css";
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
plugins: [react()],
build: {
cssMinify: true,
rollupOptions: {
output: {
manualChunks: undefined,
},
},
},
});
npm run build
# dist/assets/index-xxxxx.css — обычно 10–30 КБ gzip после purge

Проверка размера:

npx vite-bundle-visualizer

Tailwind v4 (новый движок) — импорт в CSS:

@import "tailwindcss";
@plugin "@tailwindcss/forms";

Конфиг частично переезжает в CSS @theme. Для новых проектов следуйте официальному гайду установки.

Связь с сборкой фронтенда и DevTools.


Доступность (a11y) и focus-visible

Utility-first не отменяет доступность. Минимальный набор:

Видимый фокус клавиатуры — не убирайте outline без замены:

<button class="focus-visible:outline focus-visible:outline-2
focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
Действие
</button>

focus-visible: — стиль только при навигации с клавиатуры, не при каждом клике мышью.

Конtrast — проверяйте пары text-slate-500 на bg-white (WCAG AA). text-slate-600 или темнее для мелкого текста.

Семантика HTML — Tailwind не заменяет <button> на <div onclick>:

<!-- Плохо -->
<div class="cursor-pointer" onclick="save()">Сохранить</div>

<!-- Хорошо -->
<button type="button" class="btn-primary" onclick="save()">Сохранить</button>

Skip link, aria-label на иконках, alt на картинках — как в обычном HTML.

<a href="#main"
class="sr-only focus:not-sr-only focus:absolute focus:left-4 focus:top-4
focus:z-50 focus:rounded focus:bg-white focus:px-4 focus:py-2">
Перейти к содержимому
</a>

sr-only — visually hidden, но доступно скринридеру.


Вынос компонентов

1. CSS @layer.btn-primary (см. выше)

2. React-комponent

export function Button({ children, variant = "primary", ...props }) {
const base = "rounded-lg px-4 py-2 text-sm font-semibold focus-visible:outline focus-visible:outline-2";
const variants = {
primary: "bg-indigo-600 text-white hover:bg-indigo-700 focus-visible:outline-indigo-600",
ghost: "border border-slate-300 hover:bg-slate-50",
};
return (
<button className={`${base} ${variants[variant]}`} {...props}>
{children}
</button>
);
}

3. clsx / tailwind-merge — без конфликтов padding:

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

twMerge(clsx("px-4 py-2", isLarge && "px-8 py-4", className));

4. Headless UI + Tailwind — логика dropdown/dialog без навязанных стилей Bootstrap.

5. Web Components — Tailwind в shadow DOM изолирован; см. Web Components.

Для учебных блоков без React — повторяющийся кусок HTML копируйте осознанно или используйте @layer components.


Сравнение с Bootstrap и своим CSS

ПодходКак устроеноРазмер CSS (prod)КастомизацияКогда удобно
Свой CSSсемантические .card, .btnминимальныйполнаяучёба, уникальный дизайн
Bootstrap 5готовые компоненты + utilities~25 КБ gzip + JSчерез Sass variablesадминка, MVP за день
Tailwindатомарные классы в разметке10–30 КБ gziptailwind.configReact, Vue, design systems
Bulma / Picoclass-based, без JSсреднийCSS variablesстатические сайты

Bootstrap — быстрый старт:

<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Заголовок</h5>
<a href="#" class="btn btn-primary">Кнопка</a>
</div>
</div>

Тот же блок на Tailwind — больше классов, но без борьбы с переопределением .card глобально.

Bootstrap JS — dropdown, modal, collapse. В Tailwind эквивалент — Alpine.js, Headless UI, или свой JS.

Grid — Bootstrap 12 колонок col-md-6; Tailwind — md:grid-cols-2 или md:w-1/2.

Темing — Bootstrap через $primary; Tailwind через theme.extend.colors.

КритерийBootstrapTailwind
Кривая обученияниже для первой кнопкинужно знать CSS-свойства
Консистентность в командекомпоненты по именишкала spacing/colors
Дизайн "как у всех"заметен Bootstrapзависит от вас
Интеграция Reactreact-bootstrapnative className
Документациякомпонент-ориентированнаяutility-справочник

С React классы пишут в JSX — компоненты-рецепты. С Web Components Tailwind в shadow root — отдельная тема.

Практика до Tailwind — HTML + CSS макеты Lab 110: поймёте, что px-4 — это просто padding-left + padding-right.


Типичные ошибки

СимптомЧто проверить
Классы не действуютПодключён ли CDN или сборка Tailwind
На телефоне "ломается" вёрсткаБазовые стили без префикса — для mobile; md: — для планшета и выше
Конфликт со старым CSSНе вешайте .btn и bg-blue-600 на один элемент без плана
Огромный HTMLПовтор вынесите в компонент React или в @layer components
Prod CSS 2 МБcontent paths; не CDN
dark: не работаетdarkMode: "class" и класс dark на <html>
Динамический класс пропал после buildsafelist или полные строки классов
Формы разъехались@tailwindcss/forms + явные border/ring
Нет фокуса с Tabдобавьте focus-visible:

Typography и @tailwindcss/typography

Длинные статьи энциклопедии удобно стилизовать плагином typography (prose):

npm install -D @tailwindcss/typography
plugins: [require("@tailwindcss/typography")],
<article class="prose prose-slate mx-auto max-w-3xl lg:prose-lg dark:prose-invert">
<h1>Заголовок статьи</h1>
<p>Абзац с <code>inline code</code> и ссылками.</p>
<pre><code>блок кода</code></pre>
</article>

prose-invert — палитра для тёмного фона. Кастомизация через theme.extend.typography:

typography: {
DEFAULT: {
css: {
"code::before": { content: '""' },
"code::after": { content: '""' },
},
},
},

Arbitrary values и arbitrary variants

Когда нет готового класса в шкале:

<div class="top-[117px] w-[calc(100%-2rem)] bg-[#1da1f2]">
Произвольные значения в квадратных скобках
</div>
<div class="[@media(min-width:900px)]:grid-cols-3">
Custom media query variant
</div>

Arbitrary values увеличивают CSS при JIT — не злоупотребляйте там, где хватит top-28 или токена в config.


Preflight и конфликт с legacy CSS

Tailwind Preflight (@tailwind base) — нормализация margin, border на img, button. Может конфликтовать со старым сайтом:

corePlugins: { preflight: false }, // только если знаете зачем

Или изолируйте Tailwind-страницу в iframe / отдельный entry.


Упражнения

1. Каркас HTML — сверстайте страницу-резюме только тегами по Lab 1153. Без CSS.

2. Тот же макет на чистом CSS — повторите внешний вид в отдельном style.css по Lab 110.

3. Tailwind CDN — перепишите макет из упражнения 2 с utility-классами. Сравните объём HTML и читаемость.

4. Разбор блоков — откройте Lab 1117, для каждого примера выпишите таблицу "класс → CSS-свойство" для 10 классов.

5. Адаптив — карточки в одну колонку на телефоне, три на lg:. Проверьте в DevTools device mode.

6. Dark mode — добавьте переключатель и dark: для фона и текста. Сохраните выбор в localStorage.

7. Форма — установите @tailwindcss/forms, сверстайте login с label, ошибкой (text-red-600) и disabled-кнопкой.

8. @layer — вынесите .btn-primary и .card в components.css, используйте в HTML.

9. Vite build — соберите минимальный React + Tailwind проект, сравните размер dist/assets/*.css до и после добавления 50 случайных unused классов в мёртвый файл (убедитесь, что purge их убрал).

10. a11y — пройдите форму только с Tab; виден ли focus? Добавьте skip-link.

11. Bootstrap vs Tailwind — один и тот же pricing block (3 колонки, кнопка CTA) дважды. Что короче? Что проще менять цвет бренда?

12. Связка с Web Components — прочитайте главу Web Components и опишите, почему Tailwind-классы на <my-card> не стилизуют shadow DOM внутри.


Связанные материалы