Перейти к содержанию
Mercury
Русский
Дизайн книга
Меню
Русский

UI0: токены и темы

Все значения оформления Mercury UI находятся в одной таблице. Один класс на <html> выбирает тему, которой следуют все компоненты.

Каждое значение оформления Mercury UI — цвет, типографика, отступ, радиус, тень — задано пользовательским свойством в одном файле: fiberfx/ui/src/styles/tokens.css. Его читают компоненты и ваши стили; тема — другой набор значений под теми же именами.

Единая таблица

Таблицу можно импортировать самостоятельно через @fiberfx/ui/tokens.css; полная таблица стилей @fiberfx/ui/styles.css импортирует её первой. Содержимое по порядку:

  1. Локально размещённые шрифты: DM Sans (400, 500, 700), DM Mono (300, 400, 500), DM Serif Display (400), каждый в обычном и курсивном начертании.
  2. Цветовые шкалы: исходные ступени.
  3. Семантические токены: имена для компонентов, каждое ссылается на ступень.
  4. Типографика, радиусы, отступы и тени.
  5. Тёмная тема: новые значения шкал, полупрозрачных слоёв, колец фокуса и теней.
  6. Стили элементов: html, body, от h1 до h5, p, small, code, pre, a и несколько классов — всё через токены.

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

Цветовые шкалы

Шкалы состоят из двенадцати ступеней: 1–3 — фоны, 4–8 — интерактивные поверхности, 9 — сплошной цвет, 10–12 — текст и акценты.

Шкала Назначение Ступени
--slate-* нейтральные цвета 1–12
--iris-* фирменный цвет 1–12
--indigo-* активное состояние, информация, ссылка 1–12
--green-* положительное состояние 3, 9, 11
--red-* отрицательное состояние 3, 9, 11
--orange-* предостережение 3, 9, 11
--plum-* знакомство с возможностями 3, 9, 11

Значение ступени — тройка RGB без rgb(), например --iris-9: 91 91 214. Поэтому один токен можно использовать и для непрозрачного цвета, и для цвета с альфа-каналом.

Семантические токены

Компонент не читает шкалу напрямую. Он читает семантический токен с именем <role>-<intent>-<variant>-<state>:

  • роль: bg, fg, border или shadow;
  • назначение: primary, secondary, tertiary, brand, active, positive, negative, caution, discovery, info, inverse, disabled;
  • вариант: solid по умолчанию, subtle или muted;
  • состояние: default, hover, pressed или disabled.

Семейства:

  • Поверхности: --bg-primary — страница; --bg-secondary — приподнятая поверхность; --bg-tertiary — углублённая, например блок кода; --bg-elevated — popover или модальное окно; --bg-inverse, --bg-disabled.
  • Фирменный цвет и активное состояние: --bg-brand, --bg-brand-hover, --bg-brand-pressed, --bg-brand-subtle, --bg-brand-muted; --bg-active, --bg-active-hover, --bg-active-subtle.
  • Статусы: --bg-positive, --bg-negative, --bg-caution, --bg-discovery, --bg-info; каждый с мягким оттенком -subtle.
  • Полупрозрачные слои: --bg-hover, --bg-pressed, --bg-selected, --bg-backdrop, --bg-overlay. Они уже содержат альфа-канал, например 28 32 36 / 0.06.
  • Текст и иконки: --fg-primary — основной текст; --fg-secondary — приглушённый; --fg-tertiary — заполнитель или подсказка; --fg-disabled, --fg-inverse; --fg-on-brand, --fg-on-active, --fg-on-positive, --fg-on-negative, --fg-on-caution, --fg-on-discovery — текст на сплошном фоне; --fg-brand, --fg-active, --fg-link, --fg-link-hover, --fg-link-visited и по одному для каждого статуса.
  • Границы: --border-primary — обычная тонкая граница; --border-secondary, --border-strong, --border-disabled, --border-focus, --border-active, --border-brand, --border-inverse и по одной для каждого статуса.
  • Кольца фокуса: --ring-focus и --ring-negative, с альфа-каналом.

Типографика, радиусы, отступы и тени

  • Гарнитуры: --font-primary — DM Sans, --font-secondary — DM Mono, --font-display — DM Serif Display. Насыщенность: --fw-regular 400, --fw-medium 500, --fw-semi-bold 600, --fw-bold 700, --fw-black 900.
  • Шкала типографики: от --text-body-100 до --text-body-500 (10–18 px), от --text-heading-100 до --text-heading-500 (18–72 px), каждая ступень — пара -size и -lh. Классы от .text-body-100 до .text-body-500 применяют ступень основного текста; от h1 до h5 и от .h1 до .h5 — ступени заголовков.
  • Радиусы: --radius-2, -4, -6, -8, -12, -16, -20, -24, -32, --radius-full.
  • Отступы: от --space-2 до --space-128, в пикселях: 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80, 96, 128.
  • Высота поверхности: от --shadow-100 до --shadow-600; 100–400 имеют два слоя, 500 и 600 — один. Это полные значения: используйте var(--shadow-200) без rgb().

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

Цветовой токен — тройка, поэтому оборачивайте его в rgb(). Остальные токены содержат полные значения:

.panel {
  background: rgb(var(--bg-secondary));
  color: rgb(var(--fg-primary));
  border: 1px solid rgb(var(--border-primary));
  border-radius: var(--radius-8);
  padding: var(--space-16);
  box-shadow: var(--shadow-200);
}
.panel:hover { background: rgb(var(--bg-hover)); }
.panel:focus-visible { box-shadow: 0 0 0 3px rgb(var(--ring-focus)); }

Так оформляется ваша раскладка. Компонент Mercury UI оформляется свойствами с перечислениями; его внутренние правила .mx-* читают те же токены, поэтому оба варианта следуют теме.

Переключение темы

По умолчанию тема светлая: :root содержит светлые значения. Тему задаёт один класс на <html>:

  • .light-theme объявляет светлые значения, как :root.
  • .dark-theme объявляет тёмные: меняются шкалы, полупрозрачные слои, кольца фокуса и тени; семантические токены заново разрешаются через них.
export function setTheme(theme: "light" | "dark") {
  const root = document.documentElement;
  root.classList.toggle("dark-theme", theme === "dark");
  root.classList.toggle("light-theme", theme === "light");
}

В приложении с Mercury UI установите класс темы до первой отрисовки, чтобы избежать вспышки другой темы. У сайта документации отдельная серверная оболочка: форма переключения отправляет POST, сохраняет выбор в HttpOnly cookie theme и возвращает читателя на страницу перенаправлением. Сервер записывает <html data-theme> и начальные стили фона; без cookie CSS следует prefers-color-scheme. Переключатель сайта документации не требует клиентского скрипта.

Класс темы работает и ниже <html>. Поскольку .dark-theme заново объявляет и семантические токены, и шкалы, обёртка .dark-theme внутри светлой страницы оформляет своё поддерево по тёмным шкалам. На это опирается @fiberfx/content: отрендеренный документ страницы оборачивается в .light-theme или .dark-theme.

Контраст

Измерения контраста сопровождают таблицу. fiberfx/ui/scripts/check-contrast.mjs измеряет все пары текста --fg-on-brand с его фонами, а также пары --fg-on-active и --fg-on-discovery в обеих темах по WCAG 2.x: 4,5 для текста, 3,0 для символа.

В тёмной теме каждая пара обязана проходить проверку. Сплошные фоны под тёмным текстом — --iris-9, --indigo-9, --plum-9 — осветлены до 4,5. В светлой теме известны четыре не проходящие пары: текст --fg-on-brand на --green-9, --orange-9, --red-9 и символ на --orange-9. Если одна из них начинает проходить, проверка падает до удаления её строки из списка: так список остаётся точным.