awesome-everything EN
↑ Обратно к восхождению

Архитектура фронтенда

Дизайн-токены: единый источник истины до любого ребрендинга

Суть Захардкоженные hex и отступы расходятся по web, iOS, Android и светлой/тёмной теме, пока ребрендинг не растягивается на месяцы. Токены делают каждое визуальное решение одним именованным значением — через три уровня и один пайплайн.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на junior-высоте — поверхность
◷ 16 min

Маркетинг утверждает ребрендинг: фирменный синий меняется с #0052CC на более тёплый #1A66FF. Оценка — «день». Уходит одиннадцать недель. Hex захардкожен в 340 web-компонентах, в Swift-расширении UIColor, в Android colors.xml, в двух email-шаблонах и в Figma-библиотеке, которую никто не может синхронизировать. Grep находит 18 разных написаний «одного и того же» синего — #0052cc, #0052CC, rgb(0,82,204), rgba(0, 82, 204, 1). У тёмной темы свои форкнутые копии. Три из них пропускают, и в прод уезжает двухцветная кнопка.

Токен — это решение с именем, а не значение с именем

Дизайн-токен — это именованная запись, хранящая дизайн-решение: цвет, отступ, радиус, размер шрифта, — так, что всё ниже по цепочке ссылается на имя, а не на сырое значение. Смысл не в том, чтобы дать #0052CC псевдоним blue600; само по себе это ничего не экономит. Смысл в том, что имя несёт намерение, а намерение — это то, что ты меняешь при ребрендинге, переключении темы или фиксе доступности.

Провал из хука — это то, что бывает без токенов: сырое значение скопировано в каждого потребителя, поэтому значение и есть источник истины, размноженный сотни раз. Нет единой вещи, которую можно отредактировать. Токен переворачивает это — одно определение, много ссылок, — тот же ход «единый источник истины», что и с производным состоянием, только применённый к дизайн-решениям, а не к рантайм-состоянию.

Примитив, семантика, компонент: три уровня

Наивная версия — дать каждому hex имя и остановиться — ломается в момент добавления тёмной темы, потому что blue600 — неправильная вещь, на которую ссылаться из кнопки. Тебе не нужно «кнопка использует синий 600». Тебе нужно «кнопка использует интерактивный цвет», и он мапится в синий 600 в светлой теме и во что-то ярче в тёмной. Фикс — три уровня, каждый ссылается на нижний:

  • Примитивные (глобальные) токены — сырая палитра: color.blue.600 = #0052CC, space.4 = 16px. Без смысла, просто варианты. Компонент никогда не должен ссылаться на них напрямую.
  • Семантические токены (алиасы) — решения с намерением: color.interactive.default = {color.blue.600}, color.surface.base, color.text.primary. Это слой, который переопределяют темы.
  • Компонентные токены — самые специфичные: button.background = {color.interactive.default}. Опциональны, но позволяют одному компоненту отклониться, не трогая семантический слой.
УровеньПримерНесётКто ссылается
Примитивcolor.blue.600 = #0052CCСырое значение, без смыслаТолько семантические токены
Семантикаcolor.interactive.default = {color.blue.600}Намерение / рольКомпоненты и темы
Компонентbutton.background = {color.interactive.default}Привязка одного компонентаОдин компонент
Почему это работает

Признак того, что в системе нет семантического уровня: grep по var(--color-blue-600) находит попадания внутри стилей кнопки, ссылки и таба. Это значит, что ребрендинг или тёмная тема обязаны тронуть каждое из них, а палитра протекла в продуктовый код. Компоненты, ссылающиеся на примитивы, — самая частая причина, по которой «токенизированная» система всё равно не может ребрендиться дёшево.

Пайплайн: один источник, много платформ

Токены пишутся один раз — всё чаще в формате W3C Design Tokens Community Group (DTCG), который достиг первой стабильной версии v2025.10 в октябре 2025. Это обычный JSON: каждый токен — объект с $value и $type, алиасы используют синтаксис ссылки {group.token}, файл имеет расширение .tokens.json и media type application/design-tokens+json. Композитные типы (типографика, тень, граница, градиент) объединяют несколько подзначений в один токен.

Этот JSON — единый источник. Билд-инструмент — Style Dictionary это эталонная реализация — читает его и трансформирует под каждую платформу. Трансформы — несущая часть: один и тот же токен space.4 становится --space-4: 1rem; для CSS (px→rem), space_4 (snake_case) в Android colors.xml и spaceFour (camelCase) в Swift. Цвет становится #0052CC для CSS, но UIColor(red:green:blue:alpha:) для iOS и 8-значным ARGB-hex (#FF0052CC, alpha первой) для Android. Одно определение токена, три корректных вывода под платформы — сгенерированных, а не скопированных руками. Этого шага генерации как раз и не хватало в ребрендинге-из-ада: билда не было, поэтому каждая платформа была ручным форком.

Расставь шаги по порядку

Расставь пайплайн дизайн-токенов от написания до стилизованной кнопки:

  1. 1 Написать токены один раз в DTCG JSON ($value, $type, ссылки {alias})
  2. 2 Style Dictionary читает источник и резолвит все алиасы
  3. 3 Запускаются трансформы под платформы (px→rem, hex→UIColor, name→snake_case)
  4. 4 Форматтеры выдают CSS custom properties, colors.xml, Swift-файл
  5. 5 Кнопка ссылается на --button-background → интерактивный цвет → синий 600

Темы и тёмный режим: переопределяй семантический слой, а не hex

На web вывод — это CSS custom properties, и здесь каскад делает работу бесплатно. Ты определяешь семантические токены на :root, затем переопределяешь те же семантические имена под селектором темы — и каскад пере-резолвит всё, что на них ссылается, мгновенно и без JS:

:root {
  --color-blue-600: #0052CC;            /* примитив */
  --color-interactive: var(--color-blue-600);  /* семантика */
}
[data-theme="dark"] {
  --color-blue-600: #4D8AFF;            /* то же имя, ярче значение */
}
.button { background: var(--color-interactive); }  /* не трогаем */

Кнопка вообще не упоминает тёмную тему. Переключи data-theme — и каждый компонент, читающий --color-interactive, перекрашивается за одну перерисовку, потому что custom properties каскадируются и наследуются как любое другое свойство. Дисциплина сеньора: компонент обязан ссылаться на семантический токен, никогда на примитив и никогда на литерал. В момент, когда кнопка хардкодит #0052CC или даже var(--color-blue-600), она выпадает из темы — и ты заново создал тот форк, который тёмная тема должна была убрать.

Поэтому же самое дешёвое принуждение — это lint-правило. stylelint-plugin-no-raw-colors (или похожее) делает захардкоженный hex вне файла примитивов ошибкой билда. Без него система эродирует за недели: кто-то в спешке вставляет hex, оно работает, оно уезжает в прод, и drift начинается заново. Токены — это соглашение, а соглашения без гейта деградируют.

Викторина

Кнопка должна автоматически перекрашиваться в тёмной теме. На что должен ссылаться её CSS?

Трейдофф, который взвешивает сеньор: сколько уровней и как скоро

Три уровня не бесплатны. Каждый слой косвенности — это хоп, который новый инженер обязан проследить (button.backgroundcolor.interactivecolor.blue.600), и место, где может спрятаться ошибка. Для продукта на пять человек с одной темой и без нативных приложений полная трёхуровневая система с билд-пайплайном — это оверинжиниринг: двух уровней (примитив + семантика) как CSS-переменных вполне достаточно, а компонентные токены ты добавляешь только когда компоненту действительно надо отклониться.

Расчёт резко меняется в момент, когда у тебя больше одного целевого вывода — web плюс iOS плюс Android, или светлая плюс тёмная плюс высококонтрастная, или white-label продукт с темами под каждого клиента. Каждая новая цель умножает цену отсутствия пайплайна: площадь drift растёт как платформы × темы. Прочтение сеньора — масштабировать систему под число целей, в которые ты реально отгружаешь, и вводить пайплайн до того, как приземлится вторая цель, а не после того, как ребрендинг выставит счёт на одиннадцать недель.

Выбери лучший вариант

Продукт отгружается на web, iOS и Android, со светлой и тёмной темами, и на следующий квартал запланирован ребрендинг. Выбери стратегию токенов.

Вспомните перед уходом
  1. 01
    Почему «токенизированная» система, которая даёт каждому hex имя, всё равно не может ребрендиться дёшево, и чего не хватает?
  2. 02
    Как один и тот же токен оказывается корректным на web, iOS и Android без того, чтобы кто-то копировал значения руками?
Итог

Дизайн-токен даёт имя дизайн-решению, чтобы каждый потребитель ссылался на имя, а не на сырое значение, — это ход «единый источник истины», применённый к цвету, отступам и типографике. Окупается трёхуровневая модель: примитивы держат сырую палитру, семантические токены несут намерение и являются слоем, который переопределяют темы, а компонентные токены позволяют одному компоненту отклониться. Пиши один раз в формате W3C DTCG JSON (стабилен как v2025.10), затем дай Style Dictionary трансформировать этот один источник в корректные CSS custom properties, iOS Swift и Android XML — сгенерированные, а не скопированные руками, чтобы платформы не разошлись. На web каскад CSS делает темизацию бесплатно: переопредели семантические имена под селектором темы, и каждый компонент перекрасится за одну перерисовку — при условии, что компоненты ссылаются на семантику, а не на примитивы или литералы. Принуждай это lint-правилом, масштабируй уровни под число целей, в которые реально отгружаешь, — и ребрендинг, который занял одиннадцать недель, становится одной правкой.

Продолжить восхождение ↑Design-токены: обзор с выбором ответа
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.