Tailwind CSS
Tailwind CSS
Основы
★ Tailwind CSS — CSS-фреймворк в стиле 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>
Рекомендуемый порядок практики:
- HTML-страницы целиком — каркас и теги
- HTML + CSS — макеты — те же задачи на чистом CSS
- Tailwind — готовые блоки — разбор каждого класса
В продакшене CDN не используют — подключают tailwindcss через npm/Vite и собирают только нужные классы. Подробнее — подключение CSS.
Как читать классы
| Класс Tailwind | CSS-смысл |
|---|---|
flex, grid | display: flex / grid |
items-center, justify-between | выравнивание во Flex |
gap-4 | gap: 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: | 1536px | ultra-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 КБ gzip | tailwind.config | React, Vue, design systems |
| Bulma / Pico | class-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.
| Критерий | Bootstrap | Tailwind |
|---|---|---|
| Кривая обучения | ниже для первой кнопки | нужно знать CSS-свойства |
| Консистентность в команде | компоненты по имени | шкала spacing/colors |
| Дизайн "как у всех" | заметен Bootstrap | зависит от вас |
| Интеграция React | react-bootstrap | native 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> |
| Динамический класс пропал после build | safelist или полные строки классов |
| Формы разъехались | @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 внутри.
Связанные материалы
- CSS — о разделе
- Работа с CSS · Flex и Grid · Адаптивность
- HTML — о разделе
- Доступность в CSS · CSS-переменные
- Web Components
- Lab — HTML страницы · Lab — CSS макеты · Lab — Tailwind блоки