Большинство наборов токенов начинаются с имён вроде blue-500 и gray-100. Их легко завести и легко прочитать, и они ломаются при первой же смене бренда. После ребрендинга blue-500 становится зелёным, и каждый компонент, который просил «синий», теперь врёт о том, что показывает.
Здесь мы описываем, как выбрать имена токенов, чтобы схема пережила этот момент: три уровня токенов, у каждого своя задача. Схема опирается на разделение значений и назначения, общее для Primer, Atlassian и Spectrum. Внедрять её можно по шагам, не переименовывая всё разом.
Коротко
- Используйте три уровня: примитивные токены хранят сырые значения, смысловые называют назначение и ссылаются на примитивы, компонентные называют часть одного компонента.
- Компоненты читают только смысловые или компонентные токены. Primer и Atlassian записывают это правило явно, уровни Spectrum устроены так же.
- Тогда ребрендинг добавляет или меняет значения на примитивном уровне и переставляет несколько ссылок в смысловых токенах. Код компонентов не меняется.
- Называйте по назначению, держитесь одной грамматики имён, а переименование считайте переименованием: распознавайте его по стабильному ID, а не по имени.
Почему плоские имена-значения ломаются
В плоском наборе один уровень: каждый токен — это значение с именем. Имя обычно описывает значение, потому что так назвать проще всего.
Выхода два, и оба болезненны. Либо оставить имена, и они будут врать. Либо переименовать все токены и тронуть каждый компонент, который их использует. Проблема не в ребрендинге. Проблема в том, что компоненту сказали, какой цвет брать, а не зачем.
Три уровня
Решение простое: разделить один уровень на три, и каждый отвечает на свой вопрос.
Примитивные токены: какие значения есть
Примитивы — это палитра и шкалы: все цвета, размеры и длительности, которые система разрешает использовать. Их называют по значению, потому что значение и есть их задача.
color.blue.500 color.blue.300 color.gray.900 space.4 radius.2В Primer от GitHub это base-токены: «базовые токены — самый нижний уровень, они напрямую соответствуют сырому значению» (Primer token names). Adobe Spectrum называет их global-токенами, с именами вроде blue-800 (Spectrum design data).
Смысловые токены: для чего значение
Смысловые токены называют назначение и ссылаются на примитив (см. примитивные и смысловые токены):
bg.accent → color.blue.500
fg.muted → color.gray.600
stack.gap.md → space.4В Primer это functional-токены, которые «представляют общие паттерны интерфейса», например bgColor-inset и borderColor-default. Atlassian собирает цветовые токены из основы, свойства и модификатора: color.background.brand.bold, color.text.subtle, color.icon.success (Atlassian design tokens). Spectrum называет их alias-токенами: accent-background-color-default ссылается на accent-color-900 в светлой теме и на accent-color-800 в тёмной.
Именно этот уровень делает возможными ребрендинг и тёмную тему, потому что меняются только его ссылки.
Компонентные токены: что нужно одному компоненту
Компонентные токены называют часть конкретного компонента и ссылаются на смысловые токены:
button.primary.bg.hover → bg.accent.hover
input.border.focus → border.focusУ Primer примеры такие: button-primary-bgColor-hover и control-danger-borderColor-rest. Правило при этом строгое: «компонентные и паттерн-токены следует использовать только в CSS компонентов». У Spectrum есть тот же уровень, например swatch-border-color со ссылкой на gray-1000.
Этот уровень необязателен. Добавляйте его, когда одному компоненту нужно отойти от смыслового значения по умолчанию или когда библиотека компонентов выпускает собственные темы. У Atlassian и Polaris, например, компонентного уровня в публичном наборе нет.
Как называют уровни публичные системы
Слова разные, разделение одно. Каждая из этих систем отделяет «какие значения у нас есть» от «для чего мы их используем».
Правило, на котором всё держится
Три уровня помогают, только если компоненты их соблюдают. Системы выше записывают это правило явно:
- Primer: базовые цветовые токены «не учитывают цветовые режимы, и их никогда не следует использовать напрямую в коде или макетах» (Primer color usage).
- Atlassian: «Выбирайте токены по смыслу, где это применимо, а не по конкретным значениям».
- Снова Primer, про компонентный уровень: компонентные токены нужны только для CSS своего компонента.
Компонент, который напрямую читает color.blue.500, перепрыгивает смысловой уровень. Он не последует ни за ребрендингом, ни за тёмной темой, и так часто начинается расхождение дизайн-системы. Atlassian представила свои токены как «важнейшее условие для тёмного режима» (Atlassian developer community). Она же выпускает плагины для ESLint и Stylelint (@atlaskit/eslint-plugin-design-system, @atlaskit/stylelint-design-system).
Грамматика имён, которую можно выдержать
Имена остаются единообразными, когда каждый токен собран из частей в одном порядке. Таксономия имён токенов Натана Кертиса (2020) перечисляет уровни: пространство имён, объект (группа компонентов, компонент, элемент), основа (категория, понятие, свойство) и модификатор (вариант, состояние, масштаб, режим). Его совет: «Включайте только те уровни, которые нужны, чтобы достаточно описать и различить намерение».
Практичная грамматика для большинства команд:
[property].[role].[emphasis].[state]
bg .accent.bold .hoverЦветовые токены обычно составляют бóльшую часть набора, поэтому в примерах категория color подразумевается. Если в вашем наборе много категорий, поставьте её первой частью, как в color.background.brand.bold у Atlassian.
Несколько правил сохраняют читаемость:
- Одно слово на одно понятие. Если есть
bg, не заводите ещё иbackground. Atlassian пишет слова полностью, Primer сокращает. Работает и то и другое, смесь не работает. - Состояние в конце.
bg.accent.hover, а неhover.bg.accent: так связанные токены сортируются рядом. - Никаких значений в смысловых именах.
fg.mutedможно,fg.grayнельзя. - Шкалы по позиции, а не по пикселям.
space.4переживёт смену базовой единицы,space.16pxне переживёт.
Как выглядит ребрендинг
Вот одна и та же кнопка до и после ребрендинга из синего в зелёный. Набор трёхуровневый, со светлым и тёмным режимом; пример условный.
color.blue.500 #2563eb
+color.green.500 #16a34a
+color.green.300 #86efac
-bg.accent light: {color.blue.500} dark: {color.blue.300}
+bg.accent light: {color.green.500} dark: {color.green.300}
button.primary.bg {bg.accent}Два новых примитива, один смысловой токен с двумя новыми значениями режимов, и ни одной правки на компонентном уровне или в коде компонентов. Кнопка читает bg.accent, а bg.accent теперь означает зелёный. В плоском наборе та же правка превращается в переименование blue-500 во всех файлах, где он встречается. Или в blue-500, в котором лежит зелёный.
Переход Shopify от плоского набора к смысловым токенам показывает другую сторону. Их старый пакет токенов, теперь архивный, использовал имена вроде color-blue-lighter и --color-blue-text (polaris-tokens). Текущий набор называет назначение и состояние: --p-color-bg-surface, --p-color-bg-surface-hover, --p-color-bg-fill-brand.
Как перевести плоский набор на три уровня
Переименовывать всё за один раз не нужно.
- Заморозьте палитру. Перенесите сегодняшние токены с именами-значениями на примитивный уровень как есть. Ничего не ломается, потому что пока ничего не переименовано.
- Добавьте смысловые токены для самых частых случаев. Фон, текст, граница и акцент подойдут как первый набор. Направьте каждый на тот примитив, который компоненты используют сегодня.
- Переводите компоненты по одному с примитивов на смысловые токены. Правило линтера, которое отмечает примитивы в коде компонентов, не даст миграции откатиться назад.
- Помечайте старые имена устаревшими, а не удаляйте их. В формате DTCG для этого есть свойство
$deprecated, и Primer по той же причине оставляет устаревшие имена со ссылкой на замену. - Удаляйте устаревшие имена, только когда линтер покажет ноль примитивов в коде компонентов.
Рискованный шаг здесь один: само переименование. Если ваши инструменты узнают токены по имени, переименование blue-500 в color.blue.500 выглядит как удаление одного токена и добавление другого. Ломаются сразу все потребители. Поэтому узнавайте токены по стабильному ID. У переменных Figma он есть, и конвейер, который его сохраняет, покажет переименование как переименование. Мы писали об этом в статье дизайн-токены из Figma в код.
Где здесь FISYCO
Мы делаем FISYCO, и он следует уровням, которые вы задали в Figma, а не навязывает свои. Переменные сохраняют группы из своих имён в Figma как сегменты пути. Алиасы остаются алиасами в сгенерированных файлах CSS и DTCG, а их Style Dictionary читает напрямую. Каждый токен отслеживается по ID переменной Figma, поэтому переименование в Figma приходит в pull request как переименование.
Подключите файл Figma и посмотрите на первый pull request — имена токенов останутся в синхроне с кодом.


