Меня зовут Игорь Пешков, я дизайнер в KODE — IT-компании, которая занимается коммерческой разработкой. Хочу рассказать вам, как исправлял проблемы с контрастом в дизайн-системе одной крупнейшей в своей области экосистемы IT-продуктов (сами понимаете — NDA).
Этот материал — обобщение и описание практического опыта. Теории здесь минимум, так что в первую очередь это будет полезно новичкам в работе с дизайн-системами и палитрами. Но надеюсь, что бывалые опытные дизайнеры тоже найдут здесь что-то полезное. Или хотя бы лишний раз в чём-то убедятся)
В чем была проблема
Сервисами экосистемы ежедневно пользуются миллионы человек разного возраста и профессий. Это совершенно разношерстная аудитория, в том числе — по особенностям зрительного восприятия. Поэтому очень важно, чтобы интерфейсы продуктов оставались доступными для всех текущих и будущих пользователей.
У доступности электронных интерфейсов существует несколько критериев. Один из них — уровень контраста контента (текста, иконок и графики) к фону страницы. Именно этот критерий мне и пришлось приводить в соответствие рекомендациям WCAG.
В начале работы проблемы с контрастом были видны невооружённым глазом и подтверждались жалобами пользователей. Однако проинспектировать интерфейсы, чтобы найти самые запущенные случаи, всё же пришлось. И такие случаи нашлись: например, в цветных бейджиках — довольно распространённых компонентах интерфейса — контраст текста к подложке местами опускался аж до 2,12:1 при норме в 4,5:1.
Но цветные бейджики — это не самое страшное. Второстепенный текст, который встречается в интерфейсах без преувеличения повсюду, буквально на каждом экране и почти в каждой строке, показал значение контраста 3,51:1.
Анализ палитры
Первое, что приходит на ум в таких случаях — посмотреть в базовую палитру и выбрать оттуда более подходящие по контрасту тона. Но если бы на этом всё закончилось, то и материал этот не вышел бы.
Текущая палитра оказалась довольно мала, чтобы разгуляться с выбором подходящих тонов для контента. Но ведь никто не запрещает её расширить, так? Нужно только понять, как именно были образованы тона и добавить новые таким же способом. Однако основная проблема этой палитры и пряталась именно в способе образования тонов. Она была спроектирована без учёта особенностей восприятия человеком разных оттенков. Для всех оттенков в палитре был выбран один и тот же подход генерации тоновых растяжек — изменение прозрачности базового цвета с наложением его на чистый белый.
Отсюда — отсутствие консистентности по светимости. То есть 80% синий, например, нельзя было бы не глядя заменить на 80% оранжевый из-за существенной разницы в контрасте этих двух тонов к одному и тому же фону. Не говоря уже о комбинации цветного фона и контента, как в тех же бейджиках.
Это рисовало неутешительную перспективу. Даже если бы я добавил тонов к текущей палитре и подобрал подходящее сочетание фон/контент для оранжевого бейджика, не факт, что оно подошло бы и для остальных. Стало ясно, что текущая палитра не совсем пригодна для решения проблемы и надо проектировать новую, отвечающую всем требованиям по улучшению доступности, гибкую и достаточно объёмную, чтобы покрыть максимальное количество текущих и возможных будущих потребностей.
Поиск инструмента
Совершенно очевидно, что для проектирования палитры, обслуживающей такое большое количество продуктов (читай — непредсказуемых кейсов), не подойдёт старый добрый способ «на глаз». Нужны инструменты, автоматизирующие и ускоряющие процесс, позволяющие провернуть большее количество итераций в единицу времени.
В процессе поиска я вспомнил об опыте команды дизайн-системы Adobe Spectrum. В своём материале Нэйт Болдуин, системный дизайнер Spectrum, как раз описывал похожий случай — исправление проблем с непредсказуемым контрастом в продуктах Adobe. Решением тогда стал кастомный инструмент Leonardo. Он генерировал тоновые растяжки для любых оттенков согласно заранее установленным настройкам контраста по WCAG к любому выбранному вручную фону. Спасибо команде за то, что открыли доступ к Leonardo для всех желающих бесплатно и без смс — на нем я и остановился.
Работа в Leonardo. Нейтральные оттенки
Чтобы сгенерировать растяжку тонов в Leonardo, для начала нужно задать точки останова на градиенте нейтрального оттенка из белого в чёрный. Значение контраста тонов в этих точках будет использовано для генерации растяжек из всех остальных цветов. Этих точек может быть сколько угодно и задавать их можно либо руками, либо автоматически — распределением от самой светлой до самой тёмной. Я выбрал второй путь.
Для этого нужно было только найти в интерфейсах самую контрастную и самую неконтрастную пару тонов. С контрастной парой всё легко — это первостепенный текст к белому фону. А вот со светлой парой пришлось немного повозиться и много погулять по макетам.
Сначала я увидел самый очевидный вариант. В интерфейсах повсеместно использовались белые подложки на сером фоне страницы, которые зонировали контент по смысловым блокам — распространённая практика. Эту пару я и взял для начала и получил минимальный контраст 1.09:1.
На этом этапе мне сильно пригодились возможности Leonardo по автоматизации, потому что, сгенерировав нейтральную растяжку и все основные цветные, я понял что ошибся. Нашёл в макетах ещё менее контрастную пару — 1.03:1. Это был совсем лёгкий нейтральный фон, который использовался, например, чтобы визуально отделить строки таблицы друг от друга. Несмотря на низкое значение контраста, визуально эта пара хорошо справлялась со своей задачей — по крайней мере, на экранах хорошего качества, для экранов похуже в таблицах предусмотрена дополнительная обводка. Я переделал растяжки с учетом значения 1.03:1.
В итоге получилась такая растяжка нейтрального оттенка. И да, он не совсем нейтральный. Как и в оригинальной палитре, я использовал серый с небольшой примесью брендового — чуть позже это немного усложнит мне работу, но не сейчас.
Работа в Leonardo. Цветные оттенки
Leonardo генерирует градиент из белого в чёрный на основе одного или нескольких ключевых цветов и затем расставляет на нём точки контраста, которые мы определили ранее. Основным условием при создании новой палитры было сохранение узнаваемости интерфейсов — всё-таки это был не ребрендинг. Поэтому в качестве ключевых цветов я брал 100% тона из текущей палитры.
Я начал с основного брендового цвета — холодный индиго. На этом этапе сразу же всплыла главная проблема синих оттенков — эффект Эбни, визуальное изменение оттенка при изменении уровня яркости. Благо разработчики Leonardo позаботились о том, чтобы у нас был выбор, в каком цветовом пространстве интерполировать градиент. Я выбрал OkLCH, потому что это пространство спроектировано как перцептивно универсальное и позволяет избежать ненужного искажения оттенка на протяжении всего градиента. Подробнее об OkLCH можно почитать в блоге автора этого цветового пространства. Вот для примера сравнение градиента, сгенерированного в OkLCH, с градиентом в RGB и его более человекочитаемой модели HSL.
Как видно, в RGB и HSL оттенок некрасиво сваливается в фиолетовый, что совершенно недопустимо для основного брендового цвета всех продуктов. В OkLCH же цвет «остаётся собой» на протяжении всего градиента.
Не обошлось без проблем и с тёплыми оттенками. В них традиционно в тёмном краю градиента проявляется неприятная грязь. Быстро становится понятно, что линейные формулы тут не сработают и нужно подкручивать настройки, чтобы добиться приятного цвета. Очень хороший доклад на эту тему есть у Надежды Наширбановой. Решить эту проблему позволила возможность выбора нескольких ключевых цветов для градиента и монитор с хорошей цветопередачей)
Полупрозрачность
Во время анализа существующих интерфейсов (и просто по опыту) стало понятно, что набором непрозрачных тонов не обойтись. Необходимы были полупрозрачные варианты некоторых тонов. При этом их оттенок и предсказуемый уровень контраста неплохо было бы сохранить, поэтому я решил добавить их в базовую палитру.
Для чего вообще нужны полупрозрачные цвета в палитре дизайн-сиситемы? Обычно — для сохранения уровня контраста на разных по светимости вариантах фона. В интерфейсах нашлись случаи, когда компоненты могут быть использованы как на белом фоне подложек, так и на основном фоне страниц — сером. В этом случае нужно либо предусматривать разные варианты одного компонента и надеяться на чудо внимательность пользователей дизайн-системы. Либо дать фону самому регулировать уровень контраста в лежащих на нём компонентах, подобрав для последних полупрозрачную заливку.
Опытным путём я выяснил, каким тонам из растяжек могут понадобиться полупрозрачные аналоги и нагенерировал их с помощью другого полезнейшего инструмента — Alphredo. Есть плагин для Figma и полноценное веб-приложение, выбирайте, что нравится. Если коротко — инструмент берёт оттенок, берёт фон под ним и на основе этого подбирает полупрозрачный вариант оттенка так, что они не отличаются друг от друга. Я выбрал белый фон подложек как основной, потому что в большинстве случаев на нём располагается весь контент.
Инфобоксы с непрозрачной заливкой хорошо видны на белом фоне. Но на сером они теряются из-за практически одинакового значения светимости. Варианты же с полупрозрачной заливкой сохраняют контраст к фону. Их оттенок, призванный сообщать характер уведомления — нейтральный, опасный, успешный, при этом также остаётся различимым независимо от фона.
Безусловно, серый фон приносит в полупрозрачный оттенок какое-то количество грязи. Однако в условиях масштабов и возможной цены ошибки приходится выбирать меньшее зло.
Новая палитра
В результате всех вышеописанных танцев получилась следующая базовая палитра.
Как видно, проблемы изначальной палитры решены. Новая палитра даёт достаточное количество тонов на каждый оттенок. При этом все тона сгенерированы с учётом одних и тех же значений контраста, поэтому теперь синий №1000 легко может подменить оранжевый №1000 — и наоборот. Это создаёт уверенную базу для свободного использования цвета в интерфейсах без страха, что какое-то важное сообщение окажется нечитаемым.
Проверяем результат на практике. Возьмём примеры из начала статьи — цветные бейджики и второстепенный текст.
Как видно, уровня контраста цветных лейблов на цветных фонах теперь достаточно. К тому же, контраст больше не «скачет», а остаётся консистентным независимо от оттенка. Исключением стал только оранжевый оттенок — как я ни крутил ползунки в Leonardo, какие бы формулы сдвигов оттенка к яркости ни пробовал, мне не удалось найти тот самый идеальный оттенок. Поэтому в случае с оранжевым мы решили «подвинуться» на пару тонов светлее по базовой палитре, но так, чтобы минимальным рекомендованным значениям WCAG контент всё же соответствовал.
Второстепенный текст стал более читаемым, при этом оставаясь второстепенным по восприятию. Однако в этом случае пришлось сделать исключение и решить проблему контраста второстепенного текста уже на уровне семантической структуры цветов.
Заключение
Пожалуй, я не буду делать глубоких выводов. Как я говорил в самом начале, этот материал — скорее обобщение опыта. Однако кое-что всё-таки можно вынести.
Во-первых, старайтесь использовать современные подходы и инструменты. Это позволит значительно ускорить процесс, увеличить количество итераций, а значит — быстрее добиться желаемого результата.
Во-вторых, в случае с цветом, всё же не стоит полностью полагаться на цифры и формулы. Подкручивать «на глаз» всё-таки придётся, однако, можно свести это к разумному минимуму.
В-третьих, маловероятно, что ваша проблема уникальна. Скорее всего, её уже кто-то пытался решить и наверняка где-то можно изучить похожий опыт. Поэтому не пренебрегайте чтением и просмотром материалов по вашей теме и сохраняйте закладочки — рано или поздно они вам пригодятся.
Спасибо за внимание, буду благодарен вам за комментарии!