Термином «дизайн-система» в IT давно никого не удивишь. Компании систематизируют дизайн продуктов, придумывая свои или используя чужие инструменты для управления стилями, паттернами и компонентами.
Badoo не является исключением: с помощью нашей дизайн-системы Cosmos мы поддерживаем общие принципы дизайна для четырёх приложений, работающих на четырёх платформах.

Одна из первых и основных вещей, с которой начинается работа по созданию дизайн-системы, — это токены (или переменные), которые определяют значения разных сущностей системы.
Как это работает? Например, у вас есть приложение для двух платформ. Вместо того чтобы для каждой заново указывать в CSS-файле размер и стиль шрифтов, вы можете хранить эти значения в JSON-файле, который легко преобразуется в код для любой платформы. В дальнейшем этот файл можно использовать и в других проектах с другими кодовыми базами.
Несмотря на потенциал дизайн-токенов, во многих компаниях их структура остаётся довольно простой, что сильно ограничивает возможности их применения.
Я хочу поделиться адаптированным переводом статьи моего коллеги Кристиано Растелли (Cristiano Rastelli), который несколько лет развивает дизайн-систему Cosmos. На примере своего опыта он показывает, как работать с токенами более эффективно: добавлять метаданные и использовать их для описания свойств компонентов.
Под катом — небольшой рассказ о том, как выглядят дизайн-токены в Badoo и почему они значительно упрощают процесс разработки.
В последние месяцы я не мог не заметить, как много людей (и компаний) подразумевают под дизайн-токенами только цвет, типографику и интервалы, а в некоторых случаях — тайминг, размеры и возвышение (elevation).
Они упускают главное: дизайн-токены могут быть чем-то большим, чем всё перечисленное.
В этой статье я поделюсь своим мнением и опытом по теме и покажу, что и как можно сделать с помощью токенов.
Дизайн-токены для цветов, типографики и интервалов
Как я уже говорил, многие считают дизайн-токены «набором ключевых свойств дизайна приложения или сайта». Это простое определение часто вводит в заблуждение и ограничивает возможности применения токенов.
Например, взгляните на эту песочницу: Design System Playground. Всё, что создатели предлагают менять в ней, — это цвета и типографика.
Попробуйте этот инструмент для управления дизайн-токенами — и вы увидите, что он тоже основан на идее «ключевых» значений свойств дизайна:
Скриншот интерфейса, который используется для добавления нового дизайн-токена на сайте designtokens.dev
Посмотрите, сколько плагинов для экспорта дизайн-токенов создано для Figma, Sketch и Framer. В основе каждого из них лежит идея экспорта гранулированных и изолированных значений цветов, размера шрифтов и высоты строк, интервалов и т. д.
Изучите разделы про дизайн-токены на сайтах разных дизайн-систем: в большинстве случаев там будет написано лишь про цвета, типографику, интервалы, возвышение, тайминг, размеры и прочее.
Хочу уточнить: в этом нет ничего плохого. Но, как я сказал выше, я считаю, что дизайн-токены способны на большее.
По моему опыту, огромный потенциал и сила дизайн-токенов проявляются в полной мере тогда, когда они:
- используются для выражения свойств и значений компонентов;
- аннотируются с помощью метаинформации.
Дизайн-токены для компонентов
Нет причин не использовать дизайн-токены для описания свойств компонентов.
С технической точки зрения дизайн-токены являются упорядоченными списками пар «ключ — значение», которые описывают дизайнерские решения. То, какими правилами и ограничениями мы будем руководствоваться при описании через них интерфейса, — лишь вопрос удобства (и контекста).
В некоторых случаях (особенно когда дизайн-система находится на ранней стадии развития) целесообразно ограничиться ключевыми значениями (цветами, типографикой, интервалами). Но когда система усложняется, когда в неё добавляется всё больше и больше компонентов, то хорошо бы использовать дизайн-токены и для них.
Более того, основные цвета и шрифты меняются нечасто (например, при ребрендинге), а вот компоненты, по моему опыту, развиваются непрерывно. Например, в нашу дизайн-систему в последние месяцы было добавлено много новых компонентов. Некоторые из имеющихся были усовершенствованы, а какие-то — даже отрефакторены. Несколько компонентов были расширены с целью использования их в других контекстах или визуальных состояниях. И лишь пара цветов и один шрифт были изменены.
Как мы в Badoo используем дизайн-токены
Каждый раз при создании компонента мы обсуждаем с дизайнерами или разработчиками, которые работают над дизайн-системой, возможные состояния и варианты компонента, а также его дизайнерские решения. И затем переводим все эти спецификации в конкретные дизайн-токены.
Пример набора дизайн-токенов для компонента (Lifestyle Badge)
Вот так, к примеру, выглядит JSON-файл для компонента Lifestyle Badge (для управления токенами мы используем Style Dictionary):
{ "lifestylebadge": { "height": { "value": "34", "type": "size" }, "border_radius": { "value": "17", "type": "size" }, "padding": { "start": { "value": "{spacing.md.value}", "type": "size" }, "end": { "value": "{spacing.md.value}", "type": "size" } }, "icon_size": { "value": "{icon.size.md.value}", "type": "size" }, "spacing_icon_text": { "value": "{spacing.xsm.value}", "type": "size" }, "base": { "text_color": { "value": "{color.gray_dark.value}", "type": "color" }, "background_color": { "value": "{color.gray_light.value}", "type": "color" } }, "selected": { "text_color": { "value": "{color.white.value}", "type": "color" }, "background_color": { "value": "{color.primary.value}", "type": "color" } } } }
Эти значения преобразуются в разные форматы и распределяются по различным платформам (мобильный веб, iOS, Android) и продуктам (сейчас мы поддерживаем четыре основных бренда и несколько немарочных (white label brands)).
Как только токены для компонента добавляются в систему, разработчики, которые над ним работают, получают все необходимые дизайн-спецификации:
Так выглядят токены Lifestyle Badge под Android в нашей дизайн-системе
На первый взгляд подход выглядит нерациональным и усложняющим систему. Но мы убедились в том, что это позволяет нам распределять информацию по «потребителям» — разработчикам — надёжным и отлаженным способом, что уменьшает вероятность возникновения путаницы, недопонимания и человеческих ошибок.
Со временем разработчики начинают требовать наличия конкретных токенов при добавлении компонентов в систему. В этом случае отпадает необходимость открывать Sketch-файл (или страницу в Sympli) и выяснять размеры, цвета и спецификации компонентов. Вместо этого им достаточно обновить в своих кодовых базах версию пакета дизайн-токенов и запустить скрипт синхронизации/обновления, после чего они автоматически получат все спецификации, представленные в виде легкочитаемых имён переменных.
Также мы с помощью иллюстраций показываем, как и где определены и используются дизайн-токены компонентов.
Пример набора дизайн-токенов для другого компонента (Action Sheet). С их помощью можно выразить даже выравнивание по вертикальной оси (gravity)!
Ещё один важный аспект такого подхода заключается в том, что вы получаете все те же преимущества, что и при использовании токенов для базовых свойств дизайна.
- В сложных дизайн-системах наподобие нашей это упрощает создание многопродуктовых компонентов: это те же самые компоненты с тем же кодом, которые по-разному выглядят и работают в разных продуктах/брендах. Таким образом, снижается стоимость масштабирования — например, при добавлении новых приложений в портфолио.
- Когда дизайнер решает обновить визуальный стиль компонента (например, фоновый цвет) или его макет/геометрию (например, горизонтальный отступ), то для этого требуется лишь обновить несколько значений в одном JSON-файле и изменить в кодовой базе номер версии импортируемого токена. Больше ничего: стоимость изменений чрезвычайно низкая!
Если рассматривать дизайн-токены в качестве способа передачи информации, то разумно использовать их и для компонентов.
Метаинформация дизайн-токенов
Оба основных инструмента управления дизайн-токенами (Theo и Style Dictionary) поддерживают добавление метаданных к паре «ключ — значение». Их можно использовать для добавления комментариев и аннотаций, однако по-настоящему сила метаданных раскрывается тогда, когда их используют для создания дополнительного смыслового слоя.
Например, вы можете добавить информацию о типе значений, чтобы использовать её позднее, например при обработке значений для получения конкретных результатов. Вы можете добавить информацию о группировке, чтобы потом с её помощью организовать или отфильтровать значения так, как вам нужно. Можно добавлять самые разные виды информации в зависимости от контекста и потребностей. То есть вы добавляете то, что релевантно для вас, вашего контекста, способа применения токенов и задач.
Как мы используем метаданные
Первой метаинформацией, которую мы добавили после внедрения дизайн-токенов в нашу дизайн-систему, стала «документация/комментарий» («documentation/comment»). С её помощью мы ввели в токен дополнительные данные, которые будут отображаться на сайте дизайн-системы. Мы применили пространство имён documentation, а не просто свойство comment, на тот случай, если нам понадобится добавить больше информации: к примеру, если дизайн-токен устареет и нужно будет описать его замену.
Вот пример добавления комментария в дизайн-токен:
{ "actionsheet": { … "item": { "height": { "value": "48", "type": "size", "documentation": { "comment": "Notice: this is the 'internal' size, the border will be added as extra" } }, … } } }
А так выглядит документация этого токена:
Сразу после этого мы добавили второй вид метаинформации — «тип» ("type"). Это скорее семантическое понятие, а не программистское.
Вот примеры типов, которые мы используем:
{ "color": { "primary": { "value": "{color.palette.purple_grape.value}", "type": "color" } }, "icon": { "size": { "xsm": { "value": "10", "type": "size" } } }, "tooltip": { "shadow": { "opacity": { "value": "0.08", "type": "opacity" } }, "animation": { "timing_bounce": { "value": "0.9", "type": "time", "unit": "s" } } }, "chat": { "bubble": { "relative_width": { "value": "0.8", "type": "ratio" } } }, "actionsheet": { "gravity": { "value": "center", "type": "string" } } }
Метаданные «тип» используются в скриптах постобработки для генерирования конкретных результатов для разных платформ. Вот фрагмент кода шаблона, который используется для генерирования XML-файла под Android:
В зависимости от «типа» токена мы генерируем значения с форматированием, необходимым для Android
А это отформатированный под наши требования результат:
Сгенерированный под Android XML-файл с соответствующим форматом/типом, который зависит от метазначения "type" в токене
Позднее мы добавили третий вид метаданных: «группа» ("group"). Это важнейший вид метаинформации, который используется по многим причинам.
Фильтрация
Для некоторых продуктов и задач нам нужно создавать подмножества токенов (например, только цвета). Для этого мы добавили в словарь стилей конкретный фильтр:
Скрипт для фильтрации «правильных» цветов
Вы могли заметить, что здесь мы используем два условия: одно для выбора токенов по типу «цвет» ("color"), второе — для отсеивания любых «псевдонимов» ("alias"). Это сделано потому, что мы используем специальные вспомогательные промежуточные цвета (вроде color-palette-purple-grave) в качестве указателей на их шестнадцатеричные значения, но поскольку они не нужны нам в виде сгенерированных токенов, мы отмечаем их флагом isAlias.
Затем этот фильтр используется для генерирования файлов только с цветами:
Мы фильтруем дизайн-токены в зависимости от метаданных "type", чтобы сгенерировать файлы только с цветами
Это лишь один пример того, как с помощью метаданных можно фильтровать токены и генерировать конкретные файлы. Можно придумать много других способов применения в зависимости от ваших потребностей и контекста.
Группировка
Ещё один способ использования метаданных — группировка дизайн-токенов по определённым правилам.
Например, с помощью атрибута «группа» ("group") можно создавать списки токенов, относящихся к одной группе, а затем использовать эти списки (или ассоциативные массивы) в кодовой базе.
Сгруппируем дизайн-токены по группам в зависимости от значений цветов и размеров иконок:
// color/xxx.json { "color": { "primary": { "value": "{color.palette.purple_grape.value}", "type": "color", "group": "brand" }, … "generic_red": { "value": "{color.palette.pink_salmon.value}", "type": "color", "group": "generic" }, … "gray_dark": { "value": "#767676", "type": "color", "group": "mono" }, "feature": { "verification": { "value": "{color.palette.blue_neon.value}", "type": "color", "group": "features" }, … }, "provider": { facebook": { "value": "#4867aa", "type": "color", "group": "providers" }, … }, "others": { error": { "value": "{color.generic_red.value}", "type": "color", "group": "others" }, … } } }
// icon.json { "icon": { "size": { "xsm": { "value": "10", "type": "size", "group": "size" }, "sm": { "value": "16", "type": "size", "group": "size" }, "md": { "value": "22", "type": "size", "group": "size" }, "lg": { "value": "30", "type": "size", "group": "size" }, "xlg": { "value": "36", "type": "size", "group": "size" }, "xxlg": { "value": "46", "type": "size", "group": "size" } }, "jumbo-size": { "sm": { "value": "{brick.size.sm.value}", "type": "size", "group": "size" }, "md": { "value": "{brick.size.md.value}", "type": "size", "group": "size" }, "lg": { "value": "{brick.size.lg.value}", "type": "size", "group": "size" } } } }
// spacing.json { "spacing": { "xsm": { "value": "4", "type": "size", "group": "size" }, "sm": { "value": "8", "type": "size", "group": "size" }, "md": { "value": "12", "type": "size", "group": "size" }, "lg": { "value": "16", "type": "size", "group": "size" }, "xlg": { "value": "24", "type": "size", "group": "size" }, "xxlg": { "value": "32", "type": "size", "group": "size" }, "gap": { "value": "{spacing.lg.value}", "type": "size", "group": "size" } } }
Можно сгенерировать ассоциативные массивы в Sass (они же Sass maps, или карты):
$tokens-color-map: ( providers: ( provider-facebook: $token-color-provider-facebook, … ), mono: ( black: $token-color-black, gray-dark: $token-color-gray-dark, gray: $token-color-gray, gray-light: $token-color-gray-light, white: $token-color-white ), others: ( error: $token-color-error, … ), brand: ( primary: $token-color-primary, … ), generic: ( generic-red: $token-color-generic-red, … ), features: ( … feature-verification: $token-color-feature-verification ), ); $tokens-icon-map: ( size: ( size-xsm: $token-icon-size-xsm, size-sm: $token-icon-size-sm, size-md: $token-icon-size-md, size-lg: $token-icon-size-lg, size-xlg: $token-icon-size-xlg, size-xxlg: $token-icon-size-xxlg, jumbo-size-sm: $token-icon-jumbo-size-sm, jumbo-size-md: $token-icon-jumbo-size-md, jumbo-size-lg: $token-icon-jumbo-size-lg ), ); $tokens-spacing-map: ( size: ( xsm: $token-spacing-xsm, sm: $token-spacing-sm, md: $token-spacing-md, lg: $token-spacing-lg, xlg: $token-spacing-xlg, xxlg: $token-spacing-xxlg, gap: $token-spacing-gap ), ); ...
Теперь эти карты позволят нам объявлять подобные конструкции:

Использование в нашей кодовой базе Sass-карт, сгенерированных дизайн-токенами
Таким образом, мы не просто абстрагируемся от объявления списков классов/свойств в зависимости от цвета, размера и прочих параметров — для нас гораздо важнее то, что у разных продуктов могут быть разные списки цветов, интервалов, размеров иконок и т. д., и при этом один и тот же Sass-код теперь работает для любых списков цветов, интервалов, размеров и прочего.
Эти Sass-файлы являются универсальными и могут использоваться для компонентов разных продуктов и на разных платформах.
При добавлении или удалении цвета список обновляется автоматически. Не нужно менять код на уровне компонента или приложения. Всё управляется с помощью объявлений дизайн-токенов.
Это работает не только для CSS/Sass. Те же преимущества списков токенов, относящихся к одной группе, можно получить и в JavaScript:
На сайте дизайн-системы мы демонстрируем все возможные цвета компонентов, используя списки токенов, сгенерированные через ассоциированные с ними метаданные "group"
Это приводит нас ещё к одному способу применения — CSS-в-JS. В этом случае список возможных цветов (отступов, размеров) для компонентов становится просто циклом/картой списка объектов «ключ — значение», сгенерированным инструментом для работы с дизайн-токенами.
В рамках этого же подхода мы недавно использовали свойство "group" для генерирования TypeScript-определений. С помощью специального шаблона в словаре стилей мы можем генерировать такие файлы:
declare namespace Tokens { namespace Color { enum Providers { PROVIDER_FACEBOOK = 'provider-facebook', … } enum Mono { BLACK = 'black', GRAY_DARK = 'gray-dark', GRAY = 'gray', GRAY_LIGHT = 'gray-light', WHITE = 'white' } enum Others { ERROR = 'error', … } enum Brand { PRIMARY = 'primary', … } enum Generic { GENERIC_RED = 'generic-red', … } enum Features { … FEATURE_VERIFICATION = 'feature-verification' } type Color = Providers | Mono | Others | Brand | Generic | Features; } namespace Icon { enum Size { XSM = 'xsm', SM = 'sm', MD = 'md', LG = 'lg', XLG = 'xlg', XXLG = 'xxlg', JUMBO_SM = 'jumbo-sm', JUMBO_MD = 'jumbo-md', JUMBO_LG = 'jumbo-lg' } } namespace Spacing { enum Size { XSM = 'xsm', SM = 'sm', MD = 'md', LG = 'lg', XLG = 'xlg', XXLG = 'xxlg', GAP = 'gap' } } } export default Tokens;
Эти TypeScript-определения и перечисления позднее могут напрямую использоваться клиентскими кодовыми базами для обеспечения строгой типобезопасности (и автоматически заполняться в IDE).
В качестве ещё одного возможного использования метаданных для добавления в дизайн-токены дополнительного семантического значения, в частности взаимосвязей, можно упомянуть объявление текстовых стилей. Все мы знаем, что для создания минимально жизнеспособного текстового стиля нужно задать не меньше четырёх параметров: font-family, font-size, line-height и font-weight.
Как определить и явно объявить взаимосвязи между отдельными дизайн-токенами, чтобы создать «текстовый стиль H1»? Можно отразить это в наименованиях, чтобы все свойства одного стиля имели одинаковый префикс или суффикс. Тогда почему бы не использовать метаданные, ассоциированные с токенами, для их идентификации и фильтрации/группировки в ходе обработки?
Нам это реализовывать не нужно, но если бы потребовалось, то я однозначно воспользовался бы атрибутом метаданных, ассоциированным с разными значениями стилей.
Заключение
Основные выводы:
- Дизайн-токены — это не только способ хранения информации, но и способ её передачи.
- Дизайн-токены полезны для описания ключевых дизайн-значений, но их возможности в полной мере раскрываются при использовании для описания спецификаций UI-компонентов.
- Есть много способов придать дизайн-токенам дополнительный смысл с помощью добавления метаданных. Благодаря этому можно выделять и передавать больше информации, не ограничиваясь определением «ключ — значение».
Например, с помощью метаданных можно:
- добавлять комментарии к дизайн-токенам;
- использовать фильтры и генерировать селективные результаты;
- генерировать на основе токенов динамические списки для Sass, JavaScript, TypeScript;
- благодаря этим динамическим спискам использовать одни и те же компоненты (с одинаковым кодом) в разных продуктах и на разных платформах.
Я показал, как мы реализуем этот подход в нашей дизайн-системе. Но мы используем дизайн-токены для удовлетворения наших потребностей. Уверен, что у вас есть (или вы найдёте) множество других примеров того, как можно использовать дизайн-токены, помимо цветов, типографики и интервалов.
Всё ограничивается лишь воображением. Подумайте о том, что вы можете сделать, если добавите в токены метаинформацию, имеющую для вас конкретное значение в зависимости от того, как и где эти токены используются.
А потом обязательно расскажите об этом сообществу!
P. S. Больше о том, что такое дизайн-токены, можно узнать из онлайн-курса и выступления Джины Энн, публикации Дэнни Бэнкса, репозитория Стюарта Робсона и статьи Робина Рендла. Есть ещё репозиторий рабочей группы W3C, в который можно внести свой вклад. Чтобы получить более полное представление о том, как в Badoo используются дизайн-токены, почитайте эту статью: How to manage your Design Tokens with Style Dictionary.
ссылка на оригинал статьи https://habr.com/ru/company/badoo/blog/491948/
Добавить комментарий