Осенью 2018 года ВКонтакте представил темную тему для мобильного приложения на iOS и пообещал в ближайшее время «перевести на темную сторону» и пользователей Android-приложения. Ближайшим временем оказалась середина апреля, когда и состоялся официальный релиз темной темы на Android.
Темная тема не только полюбилась пользователям соцсети, но и помогла команде ВК изменить подход к работе с цветами в интерфейсах. Как именно? В блоге ВКонтакте на Хабре рассказал дизайнер VK Михаил Лихачев.
В сентябре мы выпустили тtмную тему официального приложения ВКонтакте для 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 и даже вышедшие за его пределы, успели стать мемом.