Каждое значение оформления Mercury UI — цвет, типографика, отступ, радиус, тень — задано пользовательским свойством в одном файле: fiberfx/ui/src/styles/tokens.css. Его читают компоненты и ваши стили; тема — другой набор значений под теми же именами.
Единая таблица
Таблицу можно импортировать самостоятельно через @fiberfx/ui/tokens.css; полная таблица стилей @fiberfx/ui/styles.css импортирует её первой. Содержимое по порядку:
- Локально размещённые шрифты: DM Sans (400, 500, 700), DM Mono (300, 400, 500), DM Serif Display (400), каждый в обычном и курсивном начертании.
- Цветовые шкалы: исходные ступени.
- Семантические токены: имена для компонентов, каждое ссылается на ступень.
- Типографика, радиусы, отступы и тени.
- Тёмная тема: новые значения шкал, полупрозрачных слоёв, колец фокуса и теней.
- Стили элементов:
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-regular400,--fw-medium500,--fw-semi-bold600,--fw-bold700,--fw-black900. - Шкала типографики: от
--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. Если одна из них начинает проходить, проверка падает до удаления её строки из списка: так список остаётся точным.