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

Вот, например, список токенов из дизайн-системы Atlassian. Смогли бы вы запомнить и скомбинировать «всего-то» сотню-другую названий?



Но если сформировать небольшую библиотеку токенов, то их комбинирование позволит создать почти полный набор визуалов. И в этой статье-воркшопе мы убедимся, что, например, всего лишь из 12 коротких токенов можно собрать интерфейс для целой операционной системы.

Меня зовут Максим Кононов, я — Product Designer в микроядерной операционной системе KasperskyOS «Лаборатории Касперского». И по сути это не просто ОС, а база для целого оркестра интерфейсов. Они образуют огромный технологический стек, содержащий множество фреймворков, используемых большим количеством разработчиков. Следовательно, и дизайн-система должна быть одна, кросс-платформенная, единая для всех продуктов — и для KasperskyOS for Mobile (ОС профессиональных мобильных устройств, то есть гаджетов для «корпоративного контура» с максимально высоком уровнем кибербезопасности), и для тонкого клиента (по сути мини-компьютера, позволяющего подключиться к удаленным рабочим столам на сервере), и для инфраструктурных веб-сервисов, и для инструментария сторонних разработчиков приложений (KasperskyOS SDK), и еще много для чего… И конечно, все везде должно работать одинаково.

Итак, открываем фигму c дизайн-системой KasperskyOS и начинаем погружение в дивный мир каши из топора жонглирования интерфейсами.

Представим интерфейс как композицию блоков и элементов



Блоки — это контейнеры для элементов и других блоков. Например: модальное окно, навигационная панель, представление.
Элементы — это все остальное. Текст, иконки, кнопки, инпуты.

У цвета блока одна простая задача: выделяться на фоне родительского блока, создавая структуру слоев.

Цвет элемента содержит задачи посложнее:

  1. Управлять вниманием пользователя, подсвечивать важное и скрывать второстепенное.
  2. Показывать состояние элемента в данный момент.
  3. Указывать, к чему приведет взаимодействие с элементом.

Блоки


Чтобы блоки выделялись на фоне друг друга, нужно сделать их контрастными, только и всего. Так для каждого следующего блока можно назначить свой цвет, который будет на пару тонов выше предыдущего. Но нам нужно использовать минимум токенов и иметь возможность масштабироваться, поэтому начнем с архитектуры.

Если уберем из интерфейса все элементы — контроллы, текст, инпуты, останется всего два блока: View и Navigation.

View — это все, на чем располагается контент приложения.
Navigation — это блок с навигацией, который управляет View. Он должен быть всегда на виду, а значит, находиться поверх View или рядом с ним.
Назначим для каждого из этих блоков свой цветовой токен с одноименным названием.



Приложение состоит из композиции View. Мы назначили им всем один цвет. Поэтому ситуации, когда View пересекаются, будем решать при помощи дополнительных правил.
Если:

  • один View находится рядом с другим — добавим между ними разделительную линию с цветом Border;
  • один View находится над другим — выясним, нужно ли блокировать содержимое нижнего View. В основном оно блокируется, но есть исключения: если несколько View можно использовать параллельно (окна в десктопной ОС) или View появляется на короткое время (уведомление в мобильной ОС);

    • блокируем содержимое — добавим между View слой Overlay;
    • не блокируем содержимое — добавим обводку Border и тень.

Итого 4 токена — View, Navigation, Border, Overlay.

Элементы


Элементы составляют большую часть интерфейса. Каждый из них передает сообщение (доносит до пользователя информацию), на элемент можно нажать, чтобы после этого произошло действие, или он может предложить пользователю что-то ввести, чтобы получить информацию обратно.

Сообщение


Внутри каждого элемента могут находиться текст, иконка, картинка или другой вложенный элемент. Назначать токены будем тексту и иконке — эти простые сущности доносят до пользователя сообщение. В отличие от книги, где сообщение одно и доносится линейно, в интерфейсе их много, они разного свойства и необходимо управлять вниманием пользователя, чтобы он считывал их в определенной последовательности.



За внимание отвечают следующие три токена:
Primary — цвет текста книги. Обычный привычный цвет.
Secondary — второстепенный цвет. Чтобы сместить акцент с Primary. Информация нужна, но не настолько важна, как Primary.
Accent — цвет, который перебивает Primary. Его видят первым, он что-то выделяет.

Определенный характер сообщению задают следующие токены:
Danger — опасность. Если произошла ошибка или вот-вот произойдет необратимое действие.
Success — сообщение об успешном действии.
Warning — предупреждение.

Нажать


Кнопка имеет широкий спектр функций и не всегда имеет пояснительный текст. Поэтому пользователь, глядя только на ее внешний вид, должен понимать, что произойдет после клика. Во-первых, при помощи фона придадим каждой кнопке соответствующий ей вид.



Кнопка передает те же сообщения, что описаны выше, воспользуемся ими.
Чтобы сделать кнопку яркой и привлекательной, применим токен к фону, для обычных повседневных кнопок применим токен к контенту. Если применить токен к фону, он становится ярким и обычный цвет контента в нем перестает работать. Поэтому добавим новый токен OnAccent, он будет использоваться для любого контента внутри ярких кнопок.

Дополнительно кнопка сообщает, что с ней происходит в данный момент:

  • Не нажата (Default) — дополнительных стилей не применяем.
  • Нажата (Active) — добавим псевдоэлемент с токеном Accent, чтобы показать это. Предположим, что ярких и активных кнопок не бывает, поэтому конфликта не будет.
  • Выбрана (Focus) — добавим внешнюю обводку с токеном Accent.
    Обводка может попасть на фон Accent, поэтому добавим небольшой отступ.
  • Заблокирована (Disabled) — добавим новый токен Disabled, окрасим в него контент, цвет фона оставим Background.

Ввести




Для элементов ввода и выбора действуют те же правила кнопок. Но здесь гораздо меньше стилевых особенностей, точнее, всего одно: каждый элемент, в который можно что-то ввести, имеет обводку. Все дополнительные состояния применяем к этой обводке. А остальные необходимые токены уже существуют.

Итого 12 токенов — View, Navigation, Background, Border, Overlay, Primary, Secondary, Accent, Danger, Success, Warning, OnAccent, Disabled.

Цвета


Добавим названиям токенов цвета, учтем возможность применения темной темы и предусмотрим удобные рычаги для кастомизации тем. Будем работать с палитрой HSL.



H — основной цвет приложения. Бренд и характер. Зеленый — деньги, желтый — солнышко и так далее.
S — насыщенность цветом. Этот параметр позволяет сделать приложение ярким и эмоциональным или тусклым и консервативным.
L — светлота. Обеспечивает контраст между токенами.
A — прозрачность. Также обеспечивает контраст.

Установим цвет бренда у параметра (H) на значении 210, классический синий цвет. Применим это значение ко всем токенам. Так, при изменении цвета бренда достаточно будет поменять одно значение, остальная система его наследует.

Разобьем список токенов на три условные группы:



  • Токены Success, Warning, Danger на общую систему не влияют. Утащим готовые значения, например, у Apple.
  • OnAccent всегда будет белым (только если ваш акцент не ярко-желтый), его тоже не берем.
  • Оставшиеся токены делим так: элемент (Primary, Secondary, Disabled, Background), акцент (Accent), фон (View, Navigation, Overlay).
  • Разместим их в цветовой палитре на максимальном удалении друг от друга.
  • В темной теме перевернем вверх ногами.
  • Получим три основных цвета в двух темах:

         LIGHT            DARK
Элемент: hsl(210 0   0)   hsl(210 0   100)
Фон:     hsl(210 0   100) hsl(210 0   0)
Акцент:  hsl(210 100 50)  hsl(210 100 50)


Акцент


Чтобы поддерживать контрастность, цвета на темном фоне должны быть светлее, чем аналогичные на светлом. Поэтому будем поднимать параметр (L), который отвечает за контраст у элементов темной темы, на 10 единиц.

Итого финальный Accent:

        LIGHT            DARK
Accent: hsl(210 100 50)  hsl(210 100 60)

Элемент


Элементы образуют композицию. Это значит, что один элемент при наложении на другой должен поддерживать одинаковый уровень контраста (не сливаться). При этом мы знаем, что каждый элемент находится внутри своего блока.

Поэтому строить цвета элементов будем на основе прозрачности (регулируем параметр A), чтобы при наложении друг на друга прозрачности складывались и получались новые цвета.

Прозрачность темных цветов поднимаем на 10 единиц, а шаг берем исходя из своего чувства прекрасного.



Итого финальные токены элементов:

            LIGHT                DARK
Primary:    hsl(210 0 0 / 100%)  hsl(210 0 100 / 100%)
Secondary:  hsl(210 0 0 / 55%)   hsl(210 0 100 / 65%)
Disabled:   hsl(210 0 0 / 25%)   hsl(210 0 100 / 35%)
Border:     hsl(210 0 0 / 15%)   hsl(210 0 100 / 25%)
Background: hsl(210 0 0 / 5%)    hsl(210 0 100 / 15%)

Фон


Цвета фона настраиваются схожим образом, но они не должны быть прозрачными (за исключением Overlay). Поэтому здесь мы управляем параметрами (S и L).



Вспомним три условных цвета, которые ранее разместили на палитре, соединим их параболой, чтобы избежать грязных цветов (их можно видеть в левой части палитры). Получим примерный диапазон, который можно использовать для выстраивания слоев фона. Чем ближе к акценту располагаем цвета, тем насыщеннее и эмоциональнее получается интерфейс. У светлых цветов диапазон выбора небольшой (почти сразу начинается каша), зато с темными можно разгуляться.

Вот наш консервативный вариант:

            LIGHT                 DARK
View:       hsl(210 0 100)        hsl(210 8  4)
Navigation: hsl(210 12 97)        hsl(210 24 12)
Overlay:    hsl(210 24 96 / 80%)  hsl(210 32 16 / 80%)

Итоговый список токенов со значениями


            LIGHT                 DARK
Primary:    hsl(210 0 0 / 100%)   hsl(210 0 100 / 100%)
Secondary:  hsl(210 0 0 / 55%)    hsl(210 0 100 / 65%)
Disabled:   hsl(210 0 0 / 25%)    hsl(210 0 100 / 35%)
Border:     hsl(210 0 0 / 15%)    hsl(210 0 100 / 25%)
Background: hsl(210 0 0 / 5%)     hsl(210 0 100 / 15%)

View:       hsl(210 0 100)        hsl(210 8 4)
Navigation: hsl(210 12 97)        hsl(210 24 12)
Overlay:    hsl(210 24 96 / 80%)  hsl(210 32 16 / 80%)

Accent:     hsl(210 100 50)       hsl(210 100 60)

OnAccent:   hsl(0 0 100)          hsl(0 0 100) 
Danger:     hsl(3 100 59)         hsl(3 100 61)
Warning:    hsl(35 100 50)        hsl(36 100 52)
Success:    hsl(135 59 49)        hsl(135 64 50)

Ниже пара примеров того, как этот список можно применить в работе дизайнеру и разработчику:




Внимательный читатель спросит, куда я дел ховеры? Чтобы не мозолить глаз, ситуативные токены описываются отдельно; здесь же описана база, которую мы используем всегда и везде.

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

Комментарии (5)


  1. udinhtml
    02.08.2024 12:52

    Я тоже как-то лет пять назад преисполнился гениальной мыслью и реализацией, где я использовал прозрачные цвета для поддержания контраста контролов к различным фонам. Минусов от этого было ровно столько же, сколько и плюсов, больше так не делал.

    Из основного: вы ничего не сможете сделать, когда прозрачность вам будет мешать, а такие ситуации будут обязательно, решается только введением дополнительных токенов цвета. Если вы будете использовать какой-то оттенок цвета в прозрачностях, то на выходе будет получаться грязь, особенно, если это зеленые и желтые, красные оттенки. Решается, как предыдущий пункт, удвоением токенов.

    Сейчас же, прозрачные цвета я использую только как дополнительные, где выборочно нужна прозрачность для какого-то из контролов или фона, а не глобально.


    1. kononovmax Автор
      02.08.2024 12:52
      +1

      В обычных интерфейсах мы пока не встречали проблем с прозрачностью, но встретили их на определенном этапе в связи с техническими ограничениями устройства, прозрачность съедала много ресурсов процессора.

      Решили проблему добавлением двух групп LightSolid и DarkSolid. В них все названия токенов совпадают. Но вместо параметра Opacity в модели HSL у элементов настраивается параметр Lightness. Когда проблема решилась просто свапнули группы обратно на Opacity

      В целом в одном интерфейсе можно использовать несколько групп одновременно. И групп этих может быть сколько угодно много. Прикладываю пример на Codepen. В нем группа задается CSS классом и комбинирование групп делает систему цветов в разы гибче

      https://codepen.io/kononovmax/pen/QWXpeXN


  1. firehacker
    02.08.2024 12:52
    +1

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

    Это цепи Маркова что ли сгенерировали этот поток слов?


    1. vit1251
      02.08.2024 12:52

      Все мы знаем, что токен — это всего лишь ключ и значение

      Я знаю, что токен это может быть строка, отпечаток пальца, а может и вовсе USB устройство. Почему внезапно карта (Map) стновиться токеном? Это какой-то проф. жаргон? Может надо читателя переключить на нужный контекст?


  1. vit1251
    02.08.2024 12:52

    Вообще выглядит как создание какой-то библиотеки UI/UX, но если это библиотека, то где полученный результат? Как этим самым UI воспользоваться? Какие требования для этого инструмента - только браузер (Electron) или ограничиться только работой под Касперский ОС? В чем различие между вашей системой и скажем существующих Gtk, Qt? Не создаете ли вы (как в том анедкдоте про стандарты) еще один ненужный стандарт, а почему не использовать стилизацию уже готового? Будет ли переносимость вашего UI и смогу ли я беззаботно взять программу и портировать под Linux, FreeBSD, Windows, MacOS и конечно Касперский ОС? А что с другими российскими системами вроде Аврора? В целом после вашей статьи у меня возникла уйма вопрсоов. Выглдит в целом как какая-то верхушка айзберга описывающая стили и дизайн, но не технические аспекты разрабатываемого продукта. Было бы интересно узнать подрпобности как этим теперь можно воспользоваться.