Меню
Поиск

Дизайн-системы · Токены и темы

Как называть токены по ролям и собрать тёмную тему без ручных правок

Тёмная тема ломается там, где слой привязан к цвету, а не к роли. В уроке — примитивы и токены с ролями, из чего собрано имя токена, как тема становится вторым набором значений в режимах Figma и почему при переключении что-то остаётся светлым. Для практики — приложение «Лесной обжарки»: панель режимов с темой и плотностью, сборка имени токена и поиск прибитого в тёмной теме.

Пример для всего урока. Приложение «Лесной обжарки» из уроков «Компоненты и варианты» и «Токены и темы», Junior. Цвета и отступы уже в переменных. Теперь магазин добавляет тёмную тему, а для планшета у бариста — плотный режим. Как подобрать цвета тёмной темы и проверить их контраст, разобрано в уроке «Цвет и контраст», Middle. Здесь — как устроить токены, чтобы тема переключалась сама.

1Примитивы и токены с ролями

Примитив говорит, какое это значение. Токен с ролью говорит, зачем оно. Для двух тем нужны оба слоя.

На прошлой ступени у «Лесной обжарки» был один слой переменных: color/accent, color/text, space/m.

Пока тема одна, этого хватает. Но в тёмной теме у акцента другое значение, у текста — тоже.

Значит, у роли должно быть два значения. А сами значения удобно держать отдельно — шкалой.

Два слоя

  • Примитивы — шкалы значений: blue/600, gray/50, space/4. Они не знают, где будут стоять, и не меняются от темы.
  • Токены с ролями — color/action, color/text/primary, space/inset/card. Они ссылаются на примитивы, и ссылка зависит от темы.

Например:

В светлой теме color/action ссылается на blue/600, в тёмной — на blue/300.

В макеты и в код экранов выходят только роли. Примитивы живут внутри системы.

Две коллекции · примитивы и роли
ПримитивыЗначение
gray/0FFFFFF
gray/9001B1F24
blue/3007AA7F0
blue/6001D5FD1
space/312
space/416
РолиLightDark
color/bg/surfacegray/0gray/850
color/text/primarygray/900gray/100
color/actionblue/600blue/300
color/text/on-actiongray/0blue/950
В ячейке роли — не код цвета, а ссылка на примитив. В Figma такая ссылка называется alias.

Не только цвет

Роль цвету нужна всегда: без неё не собрать тёмную тему.

С отступами по-разному. Atlassian обходится шкалой: space.100, space.200 и так далее.

Роли отступам нужны, когда у продукта есть режим плотности. Тогда space/inset/card в обычном режиме — space/4, а в плотном — space/3.

Проверьте себя

Перед вами имена из набора «Лесной обжарки». Где примитив, где роль, а где имя, которое придётся переделать?

Тренажёр · примитив, роль или плохое имя
  1. blue/600

  2. color/text/secondary

  3. color/bg/blue

  4. space/4

  5. color/border/focus

  6. color/catalog-button

  7. space/inset/card

  8. color/text-dark-theme

Примитив называют по месту в шкале, роль — по работе на экране. Цвет, место и тема в имени роли — признак, что имя придётся переделать.
Примитивы — внутри, роли — наружу. Экран говорит, зачем ему значение, а система решает, какое оно в каждой теме.

2Из чего собрано имя токена

Имя токена собирают из частей в одном порядке. Тогда нужный токен можно найти, не зная его заранее.

Части идут от общего к частному:

  • Категория — что это: цвет, отступ, радиус.
  • Свойство — куда он ставится: фон, текст, граница.
  • Роль — зачем: действие, вторичный текст, ошибка.
  • Состояние — когда: наведение, нажатие. Если состояния нет, части нет.

Например:

color/bg/action/hover — фон кнопки действия при наведении.

Как это устроено у Atlassian

У Atlassian тот же порядок, только частей больше.

Например:

color.background.brand.bold.hovered — цвет, фон, роль «бренд», сильное выделение, наведение.

Натан Кертис в статье «Naming Tokens in Design Systems» (2020) собирает части имени в четыре группы: пространство имён, объект, основа и модификаторы. Основа — категория, понятие и свойство: color, action, background. Понятие у Кертиса — это роль в уроке.

Общего порядка частей, пишет Кертис, нет. Сколько частей брать и в каком порядке, решает команда. Главное — один порядок на всю систему.

Попробуйте собрать имя сами.

Тренажёр · соберите имя токена

Нужен токен для фона кнопки «В корзину», когда на неё навели курсор.

color/bg/action/hover

Категория — что это

Не годится. Это уже компонентный токен. Он нужен, только если у кнопки фон отличается от всех остальных действий.

Годится. Фон кнопки — это цвет.

Не годится. Не говорит, цвет это, отступ или шрифт.

Свойство — куда ставится

Не годится. Цвет в имени. В тёмной теме и после смены бренда фон может стать другим.

Не годится. Место в имени. Та же кнопка стоит в корзине и в «Избранном».

Годится. Токен для заливки. Для подписи на кнопке будет свой — text.

Роль — зачем

Годится. Главное действие на экране. Та же роль у кнопки «Оформить заказ».

Не годится. Ступень шкалы в имени роли. Это ссылка на примитив, а не роль.

Не годится. Название кнопки, а не роль. «Купить в один клик» тоже действие, и ей понадобится свой токен.

Состояние — когда

Не годится. Описывает вид. В тёмной теме фон при наведении, наоборот, светлее.

Годится. Состояние, а не вид. Рядом будут pressed и disabled.

Не годится. Номер ничего не говорит. Через месяц никто не вспомнит, чем action/2 отличается от action/3.

Части разделены косой чертой, как группы в Figma. В коде разделитель обычно дефис или точка — как переводить имена, разобрано на следующей ступени.

Здесь урок расходится с Material 3. Там есть третий слой — компонентные токены. У кнопки свой токен фона md.comp.button.filled.container.color, и он ссылается на md.sys.color.primary. Урок заводит компонентный токен, только когда компонент правда отличается: каждый такой токен — ещё одно место, где тема может разойтись.

И с Кертисом тоже. В 2020 году режим он писал прямо в имени: …-hover-on-light и …-hover-on-dark. Сейчас режимы держит сама коллекция переменных, поэтому урок кладёт тему в режим, а не в имя: color/text/primary одно, а значений два.

Имя токена — части в одном порядке. Категория, свойство, роль, состояние. Без цвета, места и темы в имени.

3Тема — второй набор значений

Тема — это те же роли с другими значениями. Экраны не перерисовывают: они и так ссылаются на роли.

В Figma у коллекции переменных бывают режимы. У коллекции «Роли» их два: Light и Dark.

Режим ставят на фрейм, секцию или страницу. У слоёв внутри по умолчанию стоит Auto: они берут режим ближайшего родителя.

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

Коллекции независимы. Один и тот же экран может быть тёмным и плотным сразу.

Каталог · панель режимов
Каталог Найти сорт ЗёрнаМолотыйБез кофеина Кения ААСветлая обжарка · 990 ₽В корзину Эфиопия ИргачеффСветлая обжарка · 1 090 ₽В корзину КаталогИзбранноеКорзина

Режимы фрейма · Тема: Light · Плотность: Обычный

Тема коллекция «Роли»
Плотность коллекция «Плотность»

Светлая тема: фон — gray/50, карточки — gray/0, действие — blue/600.

Экран один и тот же. Меняются только режимы фрейма, а с ними — значения ролей.

Как собрать вторую тему

  1. Добавьте режим в коллекцию ролей и назовите его: Dark.
  2. Пройдите по каждой роли и поставьте ей примитив для тёмной темы.
  3. Поставьте режим Dark на фрейм и посмотрите на экран.
  4. Чините роли, а не экраны. Если что-то выглядит не так, правят значение роли в режиме Dark, а слои не трогают.

Как выбрать цвета для тёмной темы и замерить контраст, разобрано в уроке «Цвет и контраст», Middle.

Тема — режим коллекции, а не копия макета. Те же роли, другие значения. Экран переключают одним режимом на фрейме.

4Чего нет во второй теме

Тема переключает только то, что привязано к роли и получило значение в новом режиме. Остальное остаётся как было.

При переключении темы что-то может остаться светлым. Причины три.

Слой привязан к примитиву

Примитив от темы не зависит. Карточка, залитая gray/0 напрямую, в тёмной теме останется белой.

То же с кодом цвета, вписанным руками: он не меняется ни от темы, ни от правки переменной.

Роль не получила тёмного значения

Когда в коллекцию добавляют режим, Figma копирует в него значения первого столбца — режима по умолчанию. Если роль забыли пройти, в Dark у неё светлое значение.

Например:

Плашка «Осталось 3 пачки» залита color/bg/warning. В режиме Dark у роли осталось бледно-жёлтое значение из Light — и плашка светится на тёмном экране.

Значение объявлено только в одной теме

В коде то, что случится с забытым токеном, зависит от того, как записаны темы.

  • Тёмная тема переопределяет светлую. Светлые значения лежат в общем блоке, тёмный блок их меняет. Забытый токен в тёмной теме останется светлым — как в Figma.
  • У каждой темы свой блок. Тогда в тёмной теме забытого токена нет совсем. Фон станет прозрачным, и плашка исчезнет, а цвет текста возьмётся у родителя.

Поэтому список ролей проверяют по обеим темам сразу: у каждой роли два значения, и оба заполнены.

Тема переключает только роли. Примитив в слое, код цвета и роль без второго значения останутся прежними.

5Найдите прибитое в тёмной теме

Тот же каталог в режиме Dark. Четыре элемента не переключились: они привязаны к примитиву или их роль не получила тёмного значения.

Нажимайте на то, что, по-вашему, выпало из темы. Нормальные элементы тоже можно нажать: в разборе будет, почему они в порядке.

Каталог в режиме Dark · найдите прибитое
Каталог Найти сорт ЗёрнаМолотыйБез кофеина Кения АА Осталось 3 пачки В корзину Эфиопия Иргачефф Светлая обжарка · 1 090 ₽ КаталогИзбранноеКорзина
  1. Шапка «Каталог».В порядке. Фон — color/bg/surface, текст — color/text/primary. Оба переключились.
  2. Поле поиска.Прибито. Фон поля привязан к примитиву gray/0, поэтому оно осталось белым. Нужна роль — например color/bg/field.
  3. Чип «Зёрна».В порядке. Акцент стал светлее, чем в светлой теме, а подпись — тёмной. Это одна роль с двумя значениями, так и задумано.
  4. Фото сорта.В порядке. Фотографию тема не перекрашивает, и не должна.
  5. Название «Кения АА».В порядке. color/text/primary: в тёмной теме — светлый gray/100.
  6. Плашка «Осталось 3 пачки».Нет тёмного значения. Плашка привязана к роли color/bg/warning, но в режиме Dark у роли осталось светлое значение — его скопировали при создании режима и забыли поменять.
  7. Кнопка «В корзину».В порядке. color/action и color/text/on-action, оба со своими тёмными значениями.
  8. Название «Эфиопия Иргачефф».Прибито. Текст привязан к gray/900 напрямую. На тёмной карточке тёмный текст почти не виден. Нужна роль color/text/primary, как у Кении.
  9. Нижнее меню.Прибито. Меню собрано из примитивов: фон gray/50, акцент blue/600. Светлая полоса внизу тёмного экрана — первое, что заметит человек.

Все четыре найдены. Белое поле, тёмное название и светлое меню привязаны к примитивам. У плашки роль есть, но без тёмного значения. Чинят это в токенах, а не перекраской слоёв.

Нормальные элементы тоже можно нажать: вы прочитаете, почему там всё в порядке, а счётчик «Найдено» не изменится.

Как проверять свой макет

  • Переключите режим на каждом экране, а не на одном. Прибитое обычно сидит там, куда давно не заглядывали.
  • Загляните внутрь компонентов. Кнопка может быть на ролях, а иконка в ней — на примитиве.
  • Проверьте состояния: наведение, ошибку, пустой экран. Их рисуют реже, и привязки там теряются чаще.
  • Пройдите список ролей по режимам. Если значение в Dark совпадает со значением в Light, это повод спросить, так ли задумано. Бывает и нарочно: подпись поверх фотографии светлая в обеих темах. Такую роль называют по тому, на чём она стоит, — color/text/on-photo, как color/text/on-action.
Проверка темы — переключение, а не взгляд на один экран. Каждый экран, каждое состояние, каждая роль в обоих режимах.

6Задание

Переведите свой макет с примитивов на токены с ролями и соберите вторую тему заменой значений.

Часть 1 · Разделить слои, 30 минут

  1. Перенесите значения в коллекцию примитивов: шкалы цветов и отступов. Если своего проекта нет, возьмите экран каталога из этого урока.
  2. Заведите коллекцию ролей. Для каждого места на экранах ответьте, зачем там цвет или отступ, и назовите роль по частям: категория, свойство, роль, состояние.
  3. Привяжите роли к примитивам через alias.
Роли в двух темах · таблица
ПРОЕКТ: ______________________        Дата: __.__.____

РОЛЬ                    | ЗАЧЕМ                  | LIGHT       | DARK
color/bg/page           | фон экрана             | ___________ | ___________
color/bg/surface        | карточки, шапка        | ___________ | ___________
color/text/primary      | основной текст         | ___________ | ___________
color/text/secondary    | подписи, цены          | ___________ | ___________
color/action            | главное действие       | ___________ | ___________
color/text/on-action    | текст на действии      | ___________ | ___________
color/______            | ______________________ | ___________ | ___________

РОЛЬ                    | ЗАЧЕМ                  | ОБЫЧНЫЙ     | ПЛОТНЫЙ
space/inset/card        | внутри карточки        | ___________ | ___________
space/______            | ______________________ | ___________ | ___________

ПРОВЕРКА ПЕРЕКЛЮЧЕНИЕМ
экранов проверено в Dark: ____ из ____
прибитого найдено: ____ (где: ______________________)
ролей, у которых Dark = Light: ____ (так задумано? ______)
В колонках тем пишите имена примитивов, а не коды цветов: так видно, что в роли не пробралось значение руками.

Часть 2 · Собрать вторую тему, 40 минут

  1. Добавьте режим Dark в коллекцию ролей.
  2. Пройдите все роли и поставьте тёмные значения. Ни одну не пропускайте, даже если «и так сойдёт».
  3. Замерьте контраст пар текста и фона в обеих темах.

Часть 3 · Проверить переключением, 30 минут

  1. Поставьте режим Dark на каждый экран по очереди.
  2. Найдите прибитое и почините через роль, а не перекраской слоя.
  3. Заполните строки «Проверка переключением».
Как понять, что задание выполнено. Переключение темы не требует ни одной ручной правки в макете.

Что должно получиться

  • Две коллекции: примитивы и роли, роли ссылаются на примитивы.
  • Режимы Light и Dark у коллекции ролей, все значения заполнены.
  • Макет, который переключается режимом на фрейме и ничем больше.

План работы: 30 минут разделить слои, 40 — собрать тёмную тему, 30 — проверить. Около полутора часов.

Частые сложности

  • «Ролей получается пятьдесят». Сведите похожие. Если два места делают одну работу — фон карточки и фон шапки, — это одна роль.
  • «Не понимаю, роль это или вид». Спросите, что будет в тёмной теме. Если значение меняется вместе с остальными ролями, это роль.
  • «Иконки в компонентах не переключаются». Цвет иконки задан внутри главного компонента примитивом. Привяжите его к роли там.
  • «Режимов нет на нашем тарифе». На бесплатном Starter у коллекции только один режим. Режимы есть на платных тарифах — в Professional до 10 на коллекцию — и на образовательном. Без них всё равно заполните таблицу ролей в двух темах: это главная работа, а режим только переключает её значения.

7Чек-лист и ошибки

Токены готовы к теме, если

  • Примитивы и роли — в разных коллекциях, экраны берут только роли
  • Имена ролей собраны по частям в одном порядке
  • В именах нет цвета, места и темы
  • У каждой роли значение в каждом режиме
  • Тема переключается режимом на фрейме, без правок в слоях
  • Каждый экран и каждое состояние проверены переключением

Что мешает

  • Примитив в слое. Не переключается с темой.
  • Роль без тёмного значения. Показывает в тёмной теме светлое.
  • Тема в имени. «text-dark-theme» вместо второго значения у роли.
  • Цвет в имени роли. «bg/blue», которая в тёмной теме стала серой.
  • Проверка на одном экране. Прибитое находится в состояниях, куда не заглядывали.

8Три ступени темы

На первой ступени выносили значения в переменные. Здесь — называем токены по ролям и собираем темы. На следующей — держим токены одинаковыми в макете и в коде.

СтупеньЧто нужно уметьКак проверить результат
Junior Заводить переменные для цветов и отступов; привязывать к ним слои; называть по назначению; находить значения, вписанные руками Смена акцентного цвета всего макета — правка одного значения
Middle — этот урок Разделять примитивы и роли; собирать имя токена по частям; собирать вторую тему режимом; находить прибитое и роли без второго значения Переключение темы не требует ни одной ручной правки в макете
Senior Держать одинаковыми имена и значения токенов в макете и в коде; выбрать способ передачи; регулярно сверять расхождения; записать порядок добавления нового токена Новый токен проходит путь от документа до кода без ручного вмешательства
Ориентир по этой теме: вы переключаете любой экран своего макета в другую тему и заранее знаете, что ничего не останется прежним по ошибке.

Что почитать дальше

  • Дизайн-токены: полный гайд по архитектуре и неймингу (CTI vs W3C) с примерами и задачкамиХабр, Дмитрий Чаплинский, 2026 · на русском · бесплатноГайд Дмитрия Чаплинского для тех, кто сам называет токены: слои от HEX до компонента, формула «категория-свойство-роль-яркость-состояние», тёмная тема в CSS, пометка устаревших токенов и 15 задачек. В отличие от урока, компонентный слой показан нормой, а для всегда белых элементов заведён color-static-white.
  • Нейминг без боли: архитектура токенов в дизайн-системах через библиотечную структуруХабр, Илья Сластен (ПГК Диджитал), 2025 · на русском · бесплатноСтатья Ильи Сластена (ПГК Диджитал) о библиотеках Figma в четыре этажа: примитивы, стайлгайд с alias и режимами Desktop / Mobile, базовые компоненты, продукт; как спрятать примитивы через scope. В отличие от урока, в имени бывает место (border/input/focused) и состояние default, а категории color нет.
  • Modes for variablesFigma · справка на английском · бесплатноСправка Figma на английском о режимах: как добавить режим в коллекцию и почему он получает значения первого столбца, как слой берёт режим родителя (Auto), сколько режимов на каком тарифе — на бесплатном Starter их нет. Разделы об импорте и выгрузке JSON пригодятся на следующей ступени.
  • Изменить цвета и кнопки сервиса — и не сломать дизайн-системуХабр, Алексей Афонин (Yandex Cloud), 2024 · на русском · бесплатноАлексей Афонин (Yandex Cloud) показывает, как DataLens перекрасили в два новых стиля, заменив значения ролей Gravity UI: —g-color-base-brand-hover, классы светлой и тёмной темы, проверка контраста в обеих. В отличие от урока, темы заданы в CSS и Figma-стилях, а не режимами переменных.