Привет, Хабр! Меня зовут Сергей, в ispmanager я отвечаю за дизайн продукта. Сегодня я хочу рассказать о том, как мы для ispmanager темную тему делали. Присаживайтесь поудобнее – несмотря на кажущуюся простоту, это была весьма объемная работа. А значит и история выйдет большая и занимательная. Поехали!
Почему мы вообще решили делать темную тему? Если кратко, это в этом мы видели возможность не только освежить UI продукта, но и позаботиться о пользователях ispmanager. Выбор темной темы далеко не всегда обусловлен эстетическими соображениями. Для людей, работающих за ПК ночью, dark mode — скорее необходимость, чем прихоть.
Самый простой на первый взгляд путь – подбить палитру используемых цветов и разработать для каждого темную пару. Возможно, это сработало бы с молодым аккуратным продуктом, где всё изначально делалось унифицировано, экономно и по четкой документации.
Ispmanager – продукт с солидной историей. Долгое время он обходился без четких правил применения цветов и унифицированных компонентов. Кроме того, логично, что за 18 лет развития проекта через него прошло немало людей и каждый из них мог оставить свой скромный отпечаток.
Сбор данных
Театр, как известно, начинается с вешалки. А тема приложения — с палитры. Первым делом мы решили сверить фактическую палитру с той, что прописана в нашей дизайн-системе, а заодно подсчитать реальное количество используемых цветов.
Я предполагал, что в самом запущенном случае мы используем порядка 30-40 оттенков: несколько синих, несколько серых. Красный, желтый, зеленый… Забегая вперед, скажу: даже в самых смелых прогнозах я был чертовски далек от истины.
Мы с фронтенд-разработчиком Бориславом провели дотошный анализ того, как и где используется тот или иной цвет. Нам пришлось проверить буквально каждый уголок продукта, чтобы убедиться, что мы ничего не забыли. По итогу выяснилось следующее:
Палитра в дизайн-системе существенно отличается от фактической.
Некоторые цвета имеют «дубли», без которых можно (и нужно!) обойтись.
Нейминг цветов малоинформативен и требует доработки.
Компоненты остро нуждаются в унификации.
В итоговом документе мы насчитали почти 100 цветов. Согласитесь, есть пространство для оптимизации. Интерфейсы, в которых всё подчиняется регламенту и единообразию, выглядят на порядок лучше. Кроме того, подобная запущенность очень сильно удорожает разработку. Дизайнер должен думать о трудозатратах и искать наиболее оптимальные пути решения поставленных задач. Все изменения, которые были внесены в рамках работы над темной темой, снизят трудозатраты на обновление UI в будущем.
Для удобства я разложил получившуюся палитру в Figma и расписал для каждого цвета зону его применения. Чтобы начать оптимизацию, мне необходимо было по каждой группе «дублей» ответить на следующие вопросы:
Можно ли в конкретном случае «слить» два похожих цвета в один?
Как именно лучше объединять цвета, какой именно оттенок лучше подходит?
Как именовать получившиеся цвета, чтобы получилось удобно и универсально?
Задача со звездочкой — цвета, имеющие атрибут прозрачности.
Подбор и нейминг новых цветов
Итак, после подбивки текущей палитры я собрал еще один стенд и разложил на нём используемые цвета по принципу «можно слить» и «нельзя слить». А еще ставил «горчичники» (пометки), чтобы ничего не забыть и фронту было понятно, что, как и куда перемещается. Вот так выглядел этот стенд:
По итогу мне хотелось сократить палитру настолько, насколько можно – при условии сохранения юзабельности продукта. Поэтому каждый цвет и каждый оттенок я проверял вручную. Находил компонент, где используется предполагаемый дубль, и примерял новый унифицированный цвет. Выглядит хорошо? Сливаем!
Спустя какое-то время палитра приобрела следующий вид:
Согласитесь, прогресс налицо. Из ~100 цветов и оттенков я выделил всего 15-20 минимально необходимых. Единственное, что бросается в глаза – оставшийся от легаси неоптимальный нейминг. Требовалось его как следует переработать и привести названия цветов к общему знаменателю. Но как лучше это сделать?
Изначально цвета в продукте имели странную систему идентификации. Вот, например, список желтых: isp-yellow-3, isp-yellow-7, isp-yellow-8, isp-yellow-9, isp-yellow-6, isp-yellow-11. Куда делись все пропущенные порядковые номера? Загадка!
Если взять Google Material, там всё четко. Цвета разбиты по оттенкам, у каждого есть градация от светлого к темному. Аккуратная нумерация – всё по полочкам и ничего не выпадает. Соответственно, нам требовалось выработать новый подход к именованию цветов – а заодно принципы создания новых оттенков.
Нумерация? Она не даст нам достаточной гибкости. Что если нам понадобится ввести цвет, находящийся между синим №5 и синим №6?
Стандарт sRGB или X11? Недостаточно универсально и не очень удобно. Пришлось бы вводить массу лишних цветов. К тому же нам хотелось чего-то «своего».
А что, если мы для каждого получившегося цвета придумаем уникальное «фирменное» название? Причем такое, чтобы легко запоминалось и нравилось фронтенд-разработчикам. Идеально!
Пожалуй, это был самый веселый и приятный этап работы. Так в нашей дизайн-системе поселились Jon Snow, Fantomas, Nosferatu, Malewicz и прочие цветные знаменитости. Такая палитра позволяет проще разрабатывать стили, поскольку у разработчиков постепенно возникают ассоциации с названиями цветов.
Всю палитру я разбил на основную, вторичную и расширенную. Базовые цвета пришлось корректировать, так как, например, красные тексты выглядели адово даже в светлой теме. Вот, к примеру, такая градация получилась у синего:
Важный момент! Все цвета в интерфейсе нужно тестировать на контрастность по WCAG. В этом могут помочь плагины для Figma «Contrast» и «Color blind».
Что касается оттенков серого — раньше они были совершенно разнокалиберными. Одни уводило в зеленый, другие – в синий… Я полностью убрал оттенок и сделал их ахроматическими. Теперь у серых цветов остался только один параметр – светлота.
Отдельного внимания заслуживает принцип введения каждого нового цвета. Его следует строить от основного цвета путем изменения значений насыщенности и светлоты на число, кратное 5. Так мы можем гарантировать, что палитра получится однородной, а разработчики не будут «дергать» цвета из головы и при необходимости смогут просто высчитать нужный цвет из базового. Фронтенд-команда приняла решение больше не использовать «сырые» значения при разработке компонентов — только переменные с цветом (значения разрешено использовать только для определения переменной цвета).
Чтобы с палитрой было не только удобно, но еще и приятно работать, она нашпигована отсылками к кинематографу, видеоиграм, известным личностями, да и просто веселыми названиями типа «похмелье».
Работа с интерфейсом
Как нам известно из работ Якоба Нильсена, все компоненты интерфейса должны иметь отсылку к реальному миру. Кнопки нажимаются, важные элементы визуально находятся ближе к зрителю, чем второстепенные и т.п.
В случае с ispmanager – у нас достаточно много разных контекстных меню, выпадающих списков, select’ов и прочих элементов, которые требуется подсветить. Обратите внимание на скриншот ниже:
У объектов на переднем плане есть тень. Она появилась там не случайно. Тень позволяет визуально «приподнять» элемент и мягко выделить его на фоне окружения. Это не просто красивость, она на самом деле помогает пользователю лучше ориентироваться в продукте.
Но в случае с темной темой тень не сработает. Казалось бы, можно инвертировать тень, сделав ее светлой – но, поверьте мне, выглядит это отвратительно. Частично решить эту проблему помогла обводка. Взгляните на скриншот:
Благодаря обводке мы можем увидеть контур объекта. В светлой теме обводка тоже присутствует – она светлого-серого цвета и практически незаметна, но на дисплеях с плохой передачей контрастности играет важную роль. При этом от теней мы решили не отказываться. На темном фоне они, конечно, растворяются, но не на 100% благодаря тому, что мы не используем в качестве фона абсолютно черный цвет.
Добавив обводку, мы столкнулись с еще одним нюансом: интерфейсу не хватало «глубины», а в формах при открытом select’е вообще началась путаница. Поэтому все модальные окна, списки и уведомления мы покрасили в более светлый тон по принципу «то, что дальше – темнее, то, что ближе – светлее».
Динамические цвета
Первой идеей при разработке темной темы была замена всей палитры на «темную». Однако сразу возникли некоторые проблемы. И главная — это «древовидная зависимость» цветов. Давайте поясню, что это такое.
Представим, что всё приложение состоит из четырех переменных для цвета.
:root {
--isp-c-grass: #00C9A7;
--isp-c-sun: #FEFEDF;--isp-c-flower: #F3C5FF;
--isp-c-obsidian: #845EC2;
}
Дизайнер решил, что в темной теме obsidian нужно заменять на flower, а flower — на sun. Остальные цвета остаются неизменными. Таким образом цвета для темной темы будут выглядеть так:
.dark-scheme {
--isp-c-flower: var(--isp-c-sun);
--isp-c-obsidian: var(--isp-c-flower);
}
Однако теперь obsidian тоже будет иметь значение sun, так как он стал «зависимым» от цвета flower.
Следующая идея была такая: определить по компонентам переменные и присвоить им цвета. Однако ее мы тоже быстро отмели из-за большого количества компонентов.
Изучив опыт других компаний и их дизайн-системы, команда сошлась на варианте с использованием цветовых токенов (color tokens). Основная проблема в данном решении — время. Нужно изучить 600+ мест с цветами и объединить некоторые из них по общим областям применения.
Иными словами, нужно было придумать что-то такое, чтобы не пришлось анализировать все цвета в проекте, но можно было поменять некоторые из них. Так мы и пришли к идее динамических цветов.
У каждого цвета темной темы есть свой негативный «близнец», доступный в палитре статических цветов. Так, Малевич перекрашивается в Гэндальфа Серого. Каждому компоненту при его создании одним атрибутом прописывается цветовая пара «светлый/темный».
Точно тот же принцип работает для текстовых элементов, ссылок и иконок. Например, в обычном состоянии текст ссылки окрашен одним цветом, при наведении – другим. Вместо цветов A и B нам достаточно указать только код динамического цвета.
В динамической палитре каждый цвет изменяется в зависимости от текущей темы. Например, --isp-dc-cheese (префикс dc означает dynamic color) будет светло-желтым в светлой теме и темно-коричневым в темной теме. Данное решение позволяет никак не трогать текущую цветовую палитру. Достаточно в компоненте заменить статический цвет на динамический. Если же цвет вообще не изменяется от темы, можно просто использовать статический цвет.
Итоги и планы на будущее
На сегодняшний день я могу сказать, что на 90% темная тема выглядит так, как мы задумывали. Палитра и перекраска компонентов корректировалась на протяжении всего процесса разработки и тестирования, но нюансы все равно остались. Например, где-то недостает контрастности, которая хромает и в светлой теме. Иконки – это отдельная тема, достойная еще одной небольшой статьи. Поскольку передо мной стоит чуть более глобальная задача, нежели внедрение темной темы (я говорю сейчас о поднятии уровня дизайна приложения в целом), всё это со временем будет решено и выкачено на прод.
Один курьезный момент. Помните! Все макеты темных тем должны тестироваться в темном помещении. Я сам с этим столкнулся: днем макетировал в Figma, днем же проверял. А когда открыл макет ночью, оказалось, что с серыми цветами я прогадал: нужно делать их темнее. Кстати, об этом уже рассказывала моя коллега, советую ее статью к прочтению.
Разработка темной темы оказалась более комплексной и сложной задачей, нежели могло показаться на первый взгляд. Тем не менее, ее реализация позволила не только непосредственно внедрить dark mode, но и добиться других улучшений в ключе дизайна продукта:
В процессе разработки темной темы мы улучшили светлую.
Повысили доступность интерфейса за счет контрастности.
Унифицировали компоненты и выработали систему.
Снизили стоимость обновления UI в будущем.
Текущая реализация темной темы еще будет полироваться. Прямо сейчас мы работаем над еще одним компонентом UI – карточки. Они призваны решить сразу две задачи:
Альтернативное отображение списков, более понятное и дружелюбное к новичкам.
Заполнение «пустого» пространства – если у пользователя добавлен всего один сайт.
Работы много, новые фичи постоянно релизятся, над ними ведется активная работа. Подтверждение тому – дорожная карта проекта. У нас запланирован выход многих вещей: поддержка Docker, Drag’n’Drop, новый центр загрузок, центр уведомлений, виджеты для главной страницы. По ним оставляли пожелания наши пользователи, и скоро всем это можно будет увидеть в ispmanager.