webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
Tailwind CSS · Урок 3 из 6

Темы и дизайн-токены

@theme, семантические токены, светлая/тёмная тема на CSS-переменных и ручной переключатель.

Обновлено

Что такое тема

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

Итог: меняете бренд, добавляете тёмную тему или второй бренд в одном файле, не трогая компоненты.

Токены, а не захардкоженные цвета

Классическая ошибка: bg-blue-600, разбросанный по 200 файлам. Сменили бренд → правите 200 файлов.

Правильно: определить семантические дизайн-токены (какую роль играет цвет, а не какой это оттенок) и использовать их везде.

примитивные:  blue-600, stone-100          → сырая палитра
семантические: accent, bg, surface, muted  → то, что использует UI

@theme — токены, которые становятся классами

@import "tailwindcss";

@theme {
  --color-accent: #1f5fbf;
  --font-display: "IBM Plex Sans", sans-serif;
  --radius-card: 0.75rem;
}

Каждая переменная в нужном пространстве имён генерирует классы: --color-accent → bg-accent, text-accent, border-accent/50; --font-display → font-display; --radius-card → rounded-card.

Пространство имён Классы
--color-* bg-*, text-*, border-*, fill-*…
--font-* font-*
--text-* text-* (размеры)
--spacing база для p-*, m-*, gap-*
--radius-* rounded-*
--shadow-* shadow-*
--breakpoint-* sm:, md:…

Светлая / тёмная на CSS-переменных

Паттерн, который использует само это приложение:

:root {
  --bg: #f7f6f3;
  --fg: #1f1e1c;
  --accent: #1f5fbf;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #141414;
    --fg: #e9e7e2;
    --accent: #6ea4f0;
  }
}

@theme inline {
  --color-bg: var(--bg);
  --color-fg: var(--fg);
  --color-accent: var(--accent);
}

@theme inline = класс использует var(--bg) напрямую, поэтому меняется вместе с переменной. Компоненты пишут просто bg-bg text-fg — dark: им вообще не нужен.

Ручной переключатель (кнопка темы)

По умолчанию dark: следует системе. Для кнопки, которая принудительно включает тему:

@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));

[data-theme=dark] {
  --bg: #141414;
  --fg: #e9e7e2;
}

Ставите data-theme="dark" на <html> (сохраняется в cookie/localStorage, применяется до гидратации, чтобы не мигало).

Светлая / тёмная / системная без «вспышки»

У настоящего переключателя три варианта: светлая, тёмная и «как в системе». Классическая проблема: страница рендерится на сервере, не зная выбора пользователя → на долю секунды показывается не та тема (вспышка), потом JS её исправляет.

Где хранить выбор Как избежать вспышки
cookie сервер читает cookie и сразу ставит data-theme на <html> — вспышки нет (страница становится динамической)
localStorage маленький скрипт прямо в <head> ставит data-theme до отрисовки страницы — так делает библиотека next-themes
/* «системная» = без атрибута → следует prefers-color-scheme */
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));

@media (prefers-color-scheme: dark) {
  :root:not([data-theme=light]) { --bg: #141414; --fg: #e9e7e2; }
}
[data-theme=dark] { --bg: #141414; --fg: #e9e7e2; }

Добавьте ещё color-scheme: light dark на :root — полосы прокрутки и нативные элементы (input, select) подстроятся автоматически.

Несколько тем / брендов

Тот же механизм: [data-theme=ocean] { --accent: ... }. Компоненты не меняются вообще.

Правила

  1. Компоненты используют только семантические токены (bg-surface, text-muted), а не bg-stone-100.
  2. Немного токенов с хорошими именами: bg, surface, fg, muted, line, accent, success, danger.
  3. Проверяйте контраст в обеих темах.

Коротко

  • Семантические токены (bg, surface, accent), а не сырые цвета в компонентах.
  • @theme создаёт классы; @theme inline + CSS-переменные = темы, меняющиеся во время работы.
  • Тёмная тема и несколько брендов = другие значения тех же переменных.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.