Что разберём
- Примитивы и токены с ролямитренажёр
- Из чего собрано имя токенасборка
- Тема — второй набор значенийпанель режимов
- Чего нет во второй темеразбор
- Найдите прибитое в тёмной темепоиск
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/0 | FFFFFF |
gray/900 | 1B1F24 |
blue/300 | 7AA7F0 |
blue/600 | 1D5FD1 |
space/3 | 12 |
space/4 | 16 |
| Роли | Light | Dark |
|---|---|---|
color/bg/surface | gray/0 | gray/850 |
color/text/primary | gray/900 | gray/100 |
color/action | blue/600 | blue/300 |
color/text/on-action | gray/0 | blue/950 |
Не только цвет
Роль цвету нужна всегда: без неё не собрать тёмную тему.
С отступами по-разному. Atlassian обходится шкалой: space.100, space.200 и так далее.
Роли отступам нужны, когда у продукта есть режим плотности. Тогда space/inset/card в обычном режиме — space/4, а в плотном — space/3.
Проверьте себя
Перед вами имена из набора «Лесной обжарки». Где примитив, где роль, а где имя, которое придётся переделать?
blue/600ПримитивСтупень шкалы синего. Где он стоит, решают роли.
color/text/secondaryРольВторичный текст: подписи, цены, даты. В каждой теме своё значение.
color/bg/blueПлохое имяРоль, а в имени цвет. В тёмной теме фон может стать тёмно-синим или серым, и имя начнёт путать.
space/4ПримитивСтупень шкалы отступов, 16. Номер ступени — не число пикселей.
color/border/focusРольРамка фокуса. Её не берут из акцента: акцент поменяют, а рамка должна оставаться заметной.
color/catalog-buttonПлохое имяИмя по месту. Такая же кнопка в корзине возьмёт «catalog-button» — или получит свой токен-двойник.
space/inset/cardРольОтступ внутри карточки. В плотном режиме у него другое значение.
color/text-dark-themeПлохое имяТема в имени токена. Тема — это режим, а не отдельный токен: у color/text/primary два значения.
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
Имя читается слева направо: цвет, фон, действие, наведение. Рядом с ним легко найти соседей — color/bg/action/pressed и color/text/on-action.
Здесь урок расходится с 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: они берут режим ближайшего родителя.
Режимы бывают не только у цвета. Плотный вид для планшета — это ещё одна коллекция с режимами «Обычный» и «Плотный», где у ролей отступов свои значения.
Коллекции независимы. Один и тот же экран может быть тёмным и плотным сразу.
Режимы фрейма · Тема: Light · Плотность: Обычный
Светлая тема: фон — gray/50, карточки — gray/0, действие — blue/600.
Как собрать вторую тему
- Добавьте режим в коллекцию ролей и назовите его: Dark.
- Пройдите по каждой роли и поставьте ей примитив для тёмной темы.
- Поставьте режим Dark на фрейм и посмотрите на экран.
- Чините роли, а не экраны. Если что-то выглядит не так, правят значение роли в режиме Dark, а слои не трогают.
Как выбрать цвета для тёмной темы и замерить контраст, разобрано в уроке «Цвет и контраст», Middle.
4Чего нет во второй теме
Тема переключает только то, что привязано к роли и получило значение в новом режиме. Остальное остаётся как было.
При переключении темы что-то может остаться светлым. Причины три.
Слой привязан к примитиву
Примитив от темы не зависит. Карточка, залитая gray/0 напрямую, в тёмной теме останется белой.
То же с кодом цвета, вписанным руками: он не меняется ни от темы, ни от правки переменной.
Роль не получила тёмного значения
Когда в коллекцию добавляют режим, Figma копирует в него значения первого столбца — режима по умолчанию. Если роль забыли пройти, в Dark у неё светлое значение.
Например:
Плашка «Осталось 3 пачки» залита color/bg/warning. В режиме Dark у роли осталось бледно-жёлтое значение из Light — и плашка светится на тёмном экране.
Значение объявлено только в одной теме
В коде то, что случится с забытым токеном, зависит от того, как записаны темы.
- Тёмная тема переопределяет светлую. Светлые значения лежат в общем блоке, тёмный блок их меняет. Забытый токен в тёмной теме останется светлым — как в Figma.
- У каждой темы свой блок. Тогда в тёмной теме забытого токена нет совсем. Фон станет прозрачным, и плашка исчезнет, а цвет текста возьмётся у родителя.
Поэтому список ролей проверяют по обеим темам сразу: у каждой роли два значения, и оба заполнены.
5Найдите прибитое в тёмной теме
Тот же каталог в режиме Dark. Четыре элемента не переключились: они привязаны к примитиву или их роль не получила тёмного значения.
Нажимайте на то, что, по-вашему, выпало из темы. Нормальные элементы тоже можно нажать: в разборе будет, почему они в порядке.
- Шапка «Каталог».В порядке. Фон — color/bg/surface, текст — color/text/primary. Оба переключились.
- Поле поиска.Прибито. Фон поля привязан к примитиву gray/0, поэтому оно осталось белым. Нужна роль — например color/bg/field.
- Чип «Зёрна».В порядке. Акцент стал светлее, чем в светлой теме, а подпись — тёмной. Это одна роль с двумя значениями, так и задумано.
- Фото сорта.В порядке. Фотографию тема не перекрашивает, и не должна.
- Название «Кения АА».В порядке. color/text/primary: в тёмной теме — светлый gray/100.
- Плашка «Осталось 3 пачки».Нет тёмного значения. Плашка привязана к роли color/bg/warning, но в режиме Dark у роли осталось светлое значение — его скопировали при создании режима и забыли поменять.
- Кнопка «В корзину».В порядке. color/action и color/text/on-action, оба со своими тёмными значениями.
- Название «Эфиопия Иргачефф».Прибито. Текст привязан к gray/900 напрямую. На тёмной карточке тёмный текст почти не виден. Нужна роль color/text/primary, как у Кении.
- Нижнее меню.Прибито. Меню собрано из примитивов: фон gray/50, акцент blue/600. Светлая полоса внизу тёмного экрана — первое, что заметит человек.
Все четыре найдены. Белое поле, тёмное название и светлое меню привязаны к примитивам. У плашки роль есть, но без тёмного значения. Чинят это в токенах, а не перекраской слоёв.
Как проверять свой макет
- Переключите режим на каждом экране, а не на одном. Прибитое обычно сидит там, куда давно не заглядывали.
- Загляните внутрь компонентов. Кнопка может быть на ролях, а иконка в ней — на примитиве.
- Проверьте состояния: наведение, ошибку, пустой экран. Их рисуют реже, и привязки там теряются чаще.
- Пройдите список ролей по режимам. Если значение в Dark совпадает со значением в Light, это повод спросить, так ли задумано. Бывает и нарочно: подпись поверх фотографии светлая в обеих темах. Такую роль называют по тому, на чём она стоит, — color/text/on-photo, как color/text/on-action.
6Задание
Переведите свой макет с примитивов на токены с ролями и соберите вторую тему заменой значений.
Часть 1 · Разделить слои, 30 минут
- Перенесите значения в коллекцию примитивов: шкалы цветов и отступов. Если своего проекта нет, возьмите экран каталога из этого урока.
- Заведите коллекцию ролей. Для каждого места на экранах ответьте, зачем там цвет или отступ, и назовите роль по частям: категория, свойство, роль, состояние.
- Привяжите роли к примитивам через 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 минут
- Добавьте режим Dark в коллекцию ролей.
- Пройдите все роли и поставьте тёмные значения. Ни одну не пропускайте, даже если «и так сойдёт».
- Замерьте контраст пар текста и фона в обеих темах.
Часть 3 · Проверить переключением, 30 минут
- Поставьте режим Dark на каждый экран по очереди.
- Найдите прибитое и почините через роль, а не перекраской слоя.
- Заполните строки «Проверка переключением».
Что должно получиться
- Две коллекции: примитивы и роли, роли ссылаются на примитивы.
- Режимы Light и Dark у коллекции ролей, все значения заполнены.
- Макет, который переключается режимом на фрейме и ничем больше.
План работы: 30 минут разделить слои, 40 — собрать тёмную тему, 30 — проверить. Около полутора часов.
Частые сложности
- «Ролей получается пятьдесят». Сведите похожие. Если два места делают одну работу — фон карточки и фон шапки, — это одна роль.
- «Не понимаю, роль это или вид». Спросите, что будет в тёмной теме. Если значение меняется вместе с остальными ролями, это роль.
- «Иконки в компонентах не переключаются». Цвет иконки задан внутри главного компонента примитивом. Привяжите его к роли там.
- «Режимов нет на нашем тарифе». На бесплатном Starter у коллекции только один режим. Режимы есть на платных тарифах — в Professional до 10 на коллекцию — и на образовательном. Без них всё равно заполните таблицу ролей в двух темах: это главная работа, а режим только переключает её значения.
7Чек-лист и ошибки
Токены готовы к теме, если
- Примитивы и роли — в разных коллекциях, экраны берут только роли
- Имена ролей собраны по частям в одном порядке
- В именах нет цвета, места и темы
- У каждой роли значение в каждом режиме
- Тема переключается режимом на фрейме, без правок в слоях
- Каждый экран и каждое состояние проверены переключением
Что мешает
- Примитив в слое. Не переключается с темой.
- Роль без тёмного значения. Показывает в тёмной теме светлое.
- Тема в имени. «text-dark-theme» вместо второго значения у роли.
- Цвет в имени роли. «bg/blue», которая в тёмной теме стала серой.
- Проверка на одном экране. Прибитое находится в состояниях, куда не заглядывали.
8Три ступени темы
На первой ступени выносили значения в переменные. Здесь — называем токены по ролям и собираем темы. На следующей — держим токены одинаковыми в макете и в коде.
| Ступень | Что нужно уметь | Как проверить результат |
|---|---|---|
| Junior | Заводить переменные для цветов и отступов; привязывать к ним слои; называть по назначению; находить значения, вписанные руками | Смена акцентного цвета всего макета — правка одного значения |
| Middle — этот урок | Разделять примитивы и роли; собирать имя токена по частям; собирать вторую тему режимом; находить прибитое и роли без второго значения | Переключение темы не требует ни одной ручной правки в макете |
| Senior | Держать одинаковыми имена и значения токенов в макете и в коде; выбрать способ передачи; регулярно сверять расхождения; записать порядок добавления нового токена | Новый токен проходит путь от документа до кода без ручного вмешательства |
Что почитать дальше
- Дизайн-токены: полный гайд по архитектуре и неймингу (CTI vs W3C) с примерами и задачкамиГайд Дмитрия Чаплинского для тех, кто сам называет токены: слои от HEX до компонента, формула «категория-свойство-роль-яркость-состояние», тёмная тема в CSS, пометка устаревших токенов и 15 задачек. В отличие от урока, компонентный слой показан нормой, а для всегда белых элементов заведён color-static-white.
- Нейминг без боли: архитектура токенов в дизайн-системах через библиотечную структуруСтатья Ильи Сластена (ПГК Диджитал) о библиотеках Figma в четыре этажа: примитивы, стайлгайд с alias и режимами Desktop / Mobile, базовые компоненты, продукт; как спрятать примитивы через scope. В отличие от урока, в имени бывает место (border/input/focused) и состояние default, а категории color нет.
- Modes for variablesСправка Figma на английском о режимах: как добавить режим в коллекцию и почему он получает значения первого столбца, как слой берёт режим родителя (Auto), сколько режимов на каком тарифе — на бесплатном Starter их нет. Разделы об импорте и выгрузке JSON пригодятся на следующей ступени.
- Изменить цвета и кнопки сервиса — и не сломать дизайн-системуАлексей Афонин (Yandex Cloud) показывает, как DataLens перекрасили в два новых стиля, заменив значения ролей Gravity UI: —g-color-base-brand-hover, классы светлой и тёмной темы, проверка контраста в обеих. В отличие от урока, темы заданы в CSS и Figma-стилях, а не режимами переменных.