Урок 13. Справочник: директивы и классы темы
⚡ Кратко
dark: — вариант тёмной темы, @custom-variant —
способ привязать его к классу, @theme inline — семантические токены.
Директивы
| Запись | Что делает |
|---|---|
dark:bg-slate-900 | утилита в тёмной теме |
@custom-variant dark (&:where(.dark, .dark *)); | тема по классу .dark |
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *)); | тема по data-атрибуту |
@theme { … } | токены темы |
@theme inline { … } | токен подставляется как var(--…) — значение можно менять в рантайме |
Зачем нужен
inline: без него
утилита ссылается на var(--color-surface), а значение фиксируется
в момент сборки. С inline утилита получает
var(--surface) — ту самую переменную, которую вы переопределяете
в .dark. Только так тема переключается без пересборки.Полезные классы для тёмной темы
| Класс | Зачем |
|---|---|
dark:bg-slate-900 | основной фон |
dark:text-slate-100 | основной текст |
dark:border-slate-700 | границы светлее фона |
dark:ring-white/10 | замена тени |
dark:shadow-none | убрать бесполезную тень |
dark:bg-white/5 | лёгкая подсветка поверхности |
dark:opacity-90 | приглушить яркую картинку |
scheme-light-dark | сообщить браузеру о поддержке обеих тем (полосы прокрутки, системные элементы) |
⚠️ Проверить по документации: набор утилит
scheme-* для свойства color-scheme появился
в v4 — уточните доступные значения в разделе Color scheme.Набор ролей для токенов
| Токен | Роль |
|---|---|
--background / --foreground | фон страницы и основной текст |
--card / --card-foreground | поверхность карточки |
--popover / --popover-foreground | всплывающие слои |
--primary / --primary-foreground | основное действие |
--secondary, --muted, --accent | второстепенные поверхности |
--destructive | опасное действие |
--border, --input, --ring | границы, поля, фокус |
Это набор shadcn/ui — он проверен практикой и покрывает обычное приложение. Полностью разбирается в уроке 19.
Переключатель: минимальный код
// src/theme.ts — переключение темы и запоминание выбора
const KEY = 'theme'
export function applyTheme(theme: 'light' | 'dark' | 'system') {
const isDark =
theme === 'dark' ||
(theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)
document.documentElement.classList.toggle('dark', isDark)
localStorage.setItem(KEY, theme)
}
// вызывать как можно раньше, до первой отрисовки
applyTheme((localStorage.getItem(KEY) as 'light' | 'dark' | 'system') ?? 'system')
<!-- index.html: скрипт до отрисовки, чтобы не было мигания -->
<script>
const saved = localStorage.getItem('theme') ?? 'system'
const dark = saved === 'dark' ||
(saved === 'system' && matchMedia('(prefers-color-scheme: dark)').matches)
document.documentElement.classList.toggle('dark', dark)
</script>