Pull to refresh
VK
Building the Internet

Как оседлать радугу: история создания тёмной темы

Reading time 10 min
Views 40K


В сентябре мы выпустили тёмную тему официального приложения ВКонтакте для iOS, а неделю назад релиз состоялся и на Android. За этим запуском стоит большой совместный труд разработчиков и дизайнеров. Вместе мы не просто перевели VK на тёмную сторону, но и серьёзно изменили подход к работе с цветами в наших интерфейсах, упростив их выбор и снизив вероятность ошибиться и наплодить лишних стилей.


Меня зовут Михаил Лихачёв, я ведущий дизайнер VK. Расскажу, как небольшой командой адаптировали 300 экранов и систематизировали все существующие в мобильных приложениях цвета — для этого мы синхронизировали их между платформами и вынесли работу с ними в единую дизайн-систему с токенами. Поделюсь впечатлениями о том, как нам теперь с этим живётся и усложнился ли процесс дизайна.


Зачем нужна тёмная тема


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


Сейчас тёмная тема реализована не только в популярных приложениях, но и в операционных системах macOS, tvOS, в лаунчерах на Android. А её появление на всех девайсах iOS и Android наверняка не заставит себя долго ждать.


Для нас это было также реализацией долгожданной функции — о тёмной теме пользователи просили чаще всего. Она оказалась действительно востребованной — сейчас тёмной темой на iOS и Android регулярно пользуется больше 20% аудитории.


Система цветов


Перед тем как делать тёмную тему, нам нужно было переорганизовать цветовую палитру нашего приложения. Цель была следующая: как в коде, так и в дизайне не должно встречаться цветов, не входящих в фиксированную палитру. Для небольшого набора цветов будет проще подбирать соответствия в тёмной теме.


Когда мы проверили всё приложение и собрали все цвета, у нас оказалось более 200 уникальных HEX-значений. С момента релиза первой версии VK App на iOS прошло более 6 лет, приложение пережило несколько редизайнов. Где-то до сих пор сохранились необновлённые экраны, а где-то встречались ситуации, когда один и тот же цвет имел значение, отличающееся крайне несущественно. Например, один цвет в HSB мог иметь разные HEX-значения в Photoshop и Sketch.


Наше приложение очень большое. Можно сказать, что это несколько приложений в одном: новости, музыка, видео, истории, трансляции, целый мессенджер и множество других не менее важных разделов и сервисов. Мы насчитали 300−400 уникальных экранов, у каждого из которых множество состояний. У одних только новостей несколько видов отображения записей и более 15 типов прикрепляемых материалов. Для такого приложения необходима более сложная система, где цвета были бы разбиты по уровням контраста, чтобы их было проще подбирать не только для тёмной темы, но и для новых контролов.


В плане организации системы цветов нам больше всего понравился подход из Material Design. Мы подготовили в похожей системе три расширенных палитры: серую, холодно-серую и синюю. При этом мы разбили цвета по уровням контраста с условными значениями от 0 до 1000, где 0 — это самый светлый, а 1000 — самый тёмный. Эти числа и стали идентификаторами цветов вместе с названием палитры — Gray 100, Blue 300 и так далее.



При подборе цветов помогает цветовая модель HSB. В ней Hue — цветовой тон, Saturation — насыщенность, а Brightness — яркость. Hue варьируется в пределах 0−360°, и мы используем в интерфейсах фиксированное значение 212° как наш брендовый цветовой тон. Saturation и Brightness задаётся от 0 до 100%.


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


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



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


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


Подготовив предзаданную палитру, её нужно было применить в приложении, заменив более 200 имеющихся HEX-значений на новый набор из более 50-ти. И вынести все эти цвета в один файл в виде статичных переменных, где каждый цвет из палитры имеет уникальное название.


Этим занялись наши разработчики из команды инфраструктуры на iOS и Android. Ребята подготовили алгоритм, заменяющий цвет на ближайший из новой палитры, что значительно ускорило процесс. Затем мы проверили все экраны с тестировщиками, чтобы нигде не применился неподходящий цвет, и наконец взялись за тёмную тему.


Подбор цветов в тёмной теме


Мы начали примерять цвета тёмной темы на макетах главных экранов, чтобы определиться с основными используемыми оттенками. Для фона используем Gray 900 — цвет на один тон светлее чёрного, чтобы понизить контраст между фоном и текстом. Текст по этой же причине выбрали не белый, а Gray 100.


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



Таблица основных используемых цветов


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



Были и проблемные места, например модальные окна и карточки. Затемнение под ними не хотелось инвертировать в белый, и без дополнительных мер в тёмной теме обычный фон контента сливался бы с окружением. Чтобы этого избежать, для модальных карточек мы подобрали фон на тон светлее обычного, а также добавили обводку (пока только на Android), чтобы лучше отделять их от нижнего слоя.


Такие примеры показали, что нам нужна более гибкая система при реализации тёмной темы.


Техническая реализация


Подобрав на макетах соответствующие цвета для тёмной темы, мы стали переносить это дело в код.


Как мы убедились на макетах, просто внести соответствия цветов из светлой темы в тёмную — не наш вариант. Белый не везде заменится на чёрный: у элементов одного и того же цвета в светлой теме могут быть различные цвета в тёмной. Нам потребовался точный контроль над тем, как каждый элемент или группа общих стилей перекрашиваются в тёмной теме. Элементы должны менять цвет в соответствии со смыслом, вложенным в название переменной.


Мы определились со следующим подходом, где токен — это уникальное название элемента или группы элементов (например, background_content), а его значением может быть только цвет из фиксированной палитры (например, White). Мы сделали схему в JSON-формате, внутри которой прописаны все токены с их значениями в каждой теме.


Такая схема очень похожа на CSS-файл с идентификаторами элементов и их стилями, но в формате JSON.



Как выглядит схема с токенами background_content и text_primary


Всё, что у нас получилось, доступно на GitHub:


  • палитра со всеми цветами и их уникальными названиями;
  • схема со всеми токенами и их значениями в светлой и тёмной темах.

Из JSON-схемы разработчики на всех платформах генерируют код в необходимом для себя формате. Об этом с примерами кода на iOS можно почитать на слайдах Антона Спивака с его выступления на CodeFest. Доклад о реализации на Android с выступления Арсения Васильева на AppConf можно посмотреть здесь.


Напомним, что мы решили сделать строгую систему, где можно указывать цвет только из внутренней палитры, то есть в значении токена нельзя прописать произвольный HEX-код цвета. К значению токена можно добавлять параметр alpha для указания дополнительной прозрачности цвета. Этот параметр мы планируем использовать для добавления отключённого состояния и состояния при касании у контролов, чтобы не добавлять в палитру те же цвета с другой прозрачностью.


На данный момент в схеме уже больше 150 токенов. Есть как глобальные переменные, так и полностью расписанные стили каждого контрола, а также уникальные случаи, которые не поддались бы более логичному объединению, например стили бабблов из сообщений.



Примеры часто используемых токенов


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


Дальнейшая работа со схемой


Sketch и Zeplin


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


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



Так выглядит токен в виде символа


Такие токены мы добавляем рядом с макетами и отправляем всё вместе в Zeplin. Если не понятно сразу по названию или нужно уточнить, к какому элементу относятся токены, добавляем описание и делим токены на секции, описывая конкретные элементы. Используя плагин Sketch Runner для быстрого поиска по названиям символов, мы получили свой конструктор описания тёмной темы в виде аннотаций к макетам.



Добавление описания о используемых токенах


Более нативного, простого и наглядного решения, как встроить токены в макеты с дальнейшей отправкой в Zeplin, мы не нашли. Хотя в Zeplin можно давать названия уникальным цветам, в нашей схеме один цвет может использоваться сразу в нескольких токенах.


Вместо того чтобы рисовать тёмную версию для каждого из сотни экранов, мы просто описываем всё в виде токенов, тем самым экономя время дизайнеров. Все имеющиеся значения токенов у компонентов уже протестированы, и нужно лишь подставить правильные. Единой точкой правды является UI Kit — в нём можно найти не только актуальное состояние компонента, но и его используемые токены.


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


Обновления схемы


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


Подготовив обновлённую схему, мы отправляем пулл-реквест в GitHub (запрос на изменение файла), который проверяется и одобряется разработчиками. После слияния изменений разработчикам нужно подтянуть обновление UI-библиотеки, и тогда новые цвета появятся в следующей dev-сборке уже через 15 минут.


Чтобы переименовать или удалить токены в схеме, мы создаём мажорное обновление, поднимая её версию в GitHub. Это означает, что такая версия автоматически примениться не сможет, и перед обновлением версии UI-библиотеки разработчикам необходимо поддержать все изменения: обновить названия токенов, а если удаляемый токен где-то использовался, то нужно следовать комментарию из списка изменений, указывающему, какой токен нужно использовать вместо него.


Такие обновления мы можем выпускать при рефакторинге схемы: когда появилось понимание, как лучше называть токены, или если получается объединить несколько токенов в один, сохраняя при этом логику.


Кроссплатформенность и VKUI


Цвета в приложениях iOS и Android почти полностью идентичны, поэтому цветовая схема, созданная при работе с iOS, подошла и для Android. Если бы платформенные различия и были, всегда можно создать токены с суффиксом платформы.


Кроме нативных приложений у нас есть VKUI. Это набор React-компонентов, с помощью которых можно создавать интерфейсы, внешне неотличимые от наших приложений. Мы используем VKUI, чтобы создавать тестовые продукты внутри VK, а также для экранов, которыми хотелось бы управлять с сервера без обновления приложения. Кроме того, эта библиотека используется для создания сервисов VK Apps сторонними разработчиками.


VKUI собран по тому же дизайну и с тем же набором компонентов, что и нативные приложения, поэтому применение схемы и поддержка тёмной темы не потребовала новых макетов. Для нас это как ещё одна платформа, которую мы поддерживаем, только она содержит переключение между iOS и Android.


Посмотреть реализацию дизайн-системы VK в виде React-компонентов можно на VKUI Styleguide. А самое интересное то, что на этой странице можно вживую увидеть используемые нами компоненты с возможностью переключать тему и платформу.


В ближайшее время мы займёмся обновлением документации VKUI и соберём больше информации о работе нашей дизайн-команды — будет много интересного ️


Отдельная тема для мессенджера


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


Шапка в светлой теме стала белой, чтобы сфокусировать внимание на общении, а синий стал более ярким и насыщенным.



Мессенджер сделан на базе модуля сообщений из основного приложения, а это значит, что он использует те же компоненты и ту же схему для описания всех цветов. К примеру, чтобы перекрасить шапку и поиск, потребовалось заменить значения соответствующих токенов: header_background, header_tint, header_text, search_bar_background, search_bar_field_background search_bar_field_tint и других.


Довольно простым способом мы смогли за короткое время перекрасить всё приложение, создав новую тему оформления.


Работа с графикой


Весь набор иконок, используемый в приложениях, нарезан в белом цвете, и их можно легко перекрашивать, применяя токен из схемы.


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



На Android также есть 9-patch графика, которая используется, например, чтобы отрисовывать карточки с тенями. Тень в них чёрная, а заливка карточки белая. Чтобы не разбивать и здесь графику на два слоя, разработчики воспользовались режимом наложения цвета Multiply — таким образом чёрная тень не перекрашивается, и цвет применяется только на белом участке картинок, что нам и было необходимо.


Итоги


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


Единая схема, вобравшая в себя всю работу с цветами в приложении, стала мощным, но доступным для дизайнеров инструментом и упрощает будущие обновления дизайна. Повысился уровень ответственности и осмысленности при создании стилей и добавлении цветов.


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


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

Tags:
Hubs:
+37
Comments 34
Comments Comments 34

Articles

Information

Website
vk.com
Registered
Founded
Employees
5,001–10,000 employees
Location
Россия
Representative
Миша Берггрен