Начинайте с ролей, а не с инверсии образцов
Автоматическая инверсия механически меняет каналы, но смысл интерфейса не записан в числах цвета. Белая страница может стать чёрной, однако приподнятые карточки, разделители, отключённые элементы, иллюстрации и статусы потеряют исходные отношения. Сначала задайте семантические роли: холст, приподнятая поверхность, основной и вторичный текст, граница, акцент, ошибка и фокус. Значения тёмной темы назначайте этим ролям независимо. Тогда код компонентов останется стабильным, а визуальная иерархия будет управляемой. Кроме того, проверять токен с конкретной функцией проще, чем абстрактный цвет с названием вроде dark-gray-3.
- Используйте не менее двух уровней поверхности, чтобы карточки и оверлеи отделялись от страницы не только за счёт тени.
- Разделите основной и вторичный текст на роли, затем измерьте каждую роль на всех допустимых фоновых поверхностях.
- Оставляйте акцент для действий и важного выделения, чтобы декоративные элементы не спорили с интерактивными.
- Называйте токены по назначению, например text-muted или border-subtle, чтобы смена значения не требовала переписывать компоненты.
Стройте лестницу поверхностей осознанно
Тёмным поверхностям нужна достаточная разница для передачи вложенности, но крупные скачки яркости делают страницу полосатой и шумной. Начните с самого тёмного холста, затем добавьте немного более светлые значения для карточек, меню и диалогов. Если соседние заливки близки, край можно усилить границей. Тени допустимы, но на тёмном холсте они заметны слабее и не должны быть единственным сигналом границы. Проверяйте реальные сочетания вложенности: диалог над страницей, меню над карточкой, поле внутри панели. Сравнивать нужно именно соседние цвета после отрисовки.
| Роль | Пример | Что проверить |
|---|---|---|
| Холст | #101318 | Основной текст, ссылки и постоянную навигацию |
| Приподнятая поверхность | #181C22 | Границу карточки и вложенные элементы |
| Граница | #46505E | Видимый край относительно обеих заливок |
| Оверлей | #20252D | Содержимое диалога и индикатор фокуса |
Задайте явные токены и цветовую схему
Централизованные токены делают поведение тёмной темы обозримым. В этом явно тёмном примере color-scheme: dark сообщает поддерживающим браузерам, что системные элементы форм и другие части пользовательского агента нужно оформить для тёмной схемы, а пользовательские свойства хранят решения приложения. Здесь намеренно заявлена только тёмная схема, потому что показанные токены не содержат переопределений для светлой темы. Декларация не доказывает доступность и не заменяет тестирование компонентов. Пример остаётся исходным набором, а не универсальной палитрой: на результат влияют типографика, сглаживание, окружение и состояния. Блок кода одинаков во всех локалях.
:root {
color-scheme: dark;
--surface-0: #101318;
--surface-1: #181C22;
--text-primary: #F2F4F7;
--text-muted: #B8C0CC;
--border: #46505E;
--accent: #8AB4F8;
--focus: #FFD166;
}Измеряйте текст, элементы и фокус раздельно
Требования WCAG относятся к определённому содержимому и состояниям, а не дают единую оценку всей палитре. Для обычного текста критерий 1.4.3 обычно требует коэффициент контрастности не менее 4,5:1, а для подходящего крупного текста действует порог 3:1. Существенные графические объекты и визуальная информация, необходимая для распознавания компонентов, рассматриваются критерием нетекстового контраста. Внешний вид фокуса имеет отдельные требования WCAG 2.2. Измеряйте передний план относительно цвета непосредственно под ним во всех состояниях: hover, нажатие, выбор, отключение, валидация и оверлей.
- Измеряйте основной и приглушённый текст на каждой разрешённой поверхности, а не только на фоне страницы.
- Проверяйте иконки и границы, если без них нельзя распознать элемент управления или понять его состояние.
- Оценивайте индикатор фокуса относительно цветов, которых он касается: самого компонента и окружающей поверхности.
- После прозрачности и смешивания рассчитывайте контраст итогового составного цвета, потому что пользователь видит именно его.
- Проверяйте выбранное, наведённое, активное, ошибочное и отключённое состояния отдельно от состояния по умолчанию.
Управляйте акцентами, не стирая их смысл
Насыщенный акцент, удачный на белом фоне, может зрительно вибрировать на почти чёрной поверхности или не подойти для текста. Считайте заливку, текст, иконку и границу разными цветовыми парами. Для ссылки на тёмном фоне может понадобиться более светлый акцент, а для текста на акцентной кнопке — тёмный передний план. Значение статуса следует дополнять текстом, иконкой, расположением или узором, когда одного цвета недостаточно. Декоративное сияние оставляйте позади контента и проверяйте реальные пиксели под текстом. У градиента нужно измерять наименее благоприятную область, а не только его концы.
Проверяйте тему как целую систему
Завершайте работу матрицей компонентов, а не просмотром одного макета. Отрисуйте заголовки, основной текст, ссылки, кнопки, поля, таблицы, баннеры, диаграммы, меню и диалоги на всех поддерживаемых поверхностях. Пройдите интерфейс клавиатурой, осмотрите фокус при обычном и увеличенном масштабе. Там, где возможно, включите forced colors или системный высококонтрастный режим и убедитесь, что нативная семантика сохраняет состояние. Автоматический анализ полезен для стабильных пар, но оверлеи, градиенты, сглаживание и динамические состояния требуют визуальной проверки. Храните результаты рядом с токенами для повторения после изменений.
- Составьте перечень семантических токенов и укажите поверхности или компоненты, где каждый разрешено применять.
- Создайте матрицу состояний: default, hover, focus, active, selected, disabled и результаты валидации.
- Выполните детерминированный расчёт контраста сплошных цветовых пар и сохраните значения вместе с дизайн-ревью.
- До выпуска проверьте клавиатуру, масштаб и реальные устройства, а после изменения общих токенов повторите сценарии.
Первоисточники
Фактические утверждения статьи проверены по этим опубликованным спецификациям.