color theoryMay 3, 202613 min read

Цветовые системы тёмной темы: как собрать палитру, которая работает в 2 часа ночи

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

By Boone
XLinkedIn
dark mode color systems

Цветовые системы тёмной темы: как собрать палитру, которая работает в 2 часа ночи

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

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


Тёмная тема - это параллельная система, а не инверсия

В вашей светлой палитре есть токены фона, поверхности, границы, текста и акцента. В тёмной палитре нужны все те же токены, и их значения не являются инверсией светлых. Цветность ведёт себя иначе при низкой светлоте. Сдвиги оттенка происходят на перцептивной границе. То, что в светлой теме читается как чистый коралл при L 0.62, в тёмной при L 0.72 на почти чёрной поверхности расцветает вибрирующим неоном.

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


Модель высоты поверхностей

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

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

Четыре уровня - это не эстетический выбор. Это несущая конструкция. Каждый компонент вашей системы стоит на одном из этих уровней, и читаемость каждой пары «текст на поверхности» зависит от того, где в стопке вы его разместили.


Фон задаёт пол

Фон - самый глубокий уровень. Правило: никогда не используйте чистый чёрный (oklch(0 0 0)) с полной насыщенностью. Берите слегка подкрашенный почти чёрный со светлотой около 8-10 процентов. Оттенок почти всегда тёплый, потому что холодные чёрные выглядят дешевле и холоднее, чем заслуживает продукт.

Значение вроде oklch(0.10 0.012 30) даёт тёмный тёплый графит, который на любом дисплее читается как «чёрный», но избегает ощущения мёртвого вакуума от чистого чёрного. Цветности 0.012 и угла оттенка 30 градусов (лёгкий тёплый уклон) достаточно. Больше - и получится грязь. Меньше - и будет безжизненно.


Поверхность держит контент

Поверхность - уровень, на котором лежит большая часть контента, слегка приподнятый над фоном. Шаг светлоты от фона к поверхности обычно составляет 3-5 пунктов в OKLCH. Этот зазор - первый сигнал, который считывает глаз: здесь живёт контент, а фон остаётся позади.

oklch(0.14 0.010 30) на фоне oklch(0.10 0.012 30) - достаточное визуальное разделение без границы и тени. Цветность слегка падает, потому что с ростом светлоты на тёмных поверхностях цветность нужно убирать, чтобы не было грязного подмешивания в фон. При рендеринге это едва заметно, а если пропустить, то всё совершенно неправильно.


Приподнятая поверхность и оверлей

Приподнятые поверхности держат карточки и панели. Оверлеи держат модальные окна и шиты. Прогрессия светлоты продолжается: приподнятая поверхность примерно oklch(0.18 0.008 30), оверлей oklch(0.22 0.007 30). Цветность падает с каждым шагом, потому что выше в стопке значит ближе к зрителю, а такие поверхности должны ощущаться чистыми.

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


Правило обесцвечивания

Насыщенные цвета, работающие на свету, ночью обжигают. Правило: обесцвечивайте акценты на 15-25 процентов, а цветность текста и границ снижайте ещё сильнее. Речь не о том, чтобы приглушить бренд. Речь о том, как глаз обрабатывает цветность при слабом внешнем освещении.

При ярком освещении (офис в полдень) насыщенная цветность читается как живая. При слабом (стол в полночь) та же цветность читается как агрессивная, с ореолом и физически неприятная. Решение не в том, чтобы бояться цвета. Решение в калибровке. Бренд остаётся узнаваемым. Продукт перестаёт причинять боль.


Почему чисто белый текст - это ошибка

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

Правильное значение для основного текста в тёмной теме - около 90-95 процентов светлоты с лёгким тёплым оттенком. oklch(0.93 0.005 60) читается как «белый», но не даёт гало. Вторичный текст опускается до oklch(0.70 0.010 60): читается на размере основного текста, но визуально отступает на фоне первичного. Именно с этим off-white дизайнеры ошибаются чаще всего, потому что он ощущается как компромисс, а на деле это правильное значение.


Калибровка акцента сохраняет узнаваемость бренда

Акценты бренда должны читаться в тёмной теме, не теряя идентичности. Калибровка - это подъём светлоты плюс снижение цветности, а не сдвиг оттенка. Если акцент светлой темы oklch(0.62 0.22 25), то акцент тёмной - oklch(0.72 0.17 25). Тот же оттенок. Светлота выше, чтобы акцент выделялся на тёмных поверхностях. Цветность ниже, чтобы не было гало.

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


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

Проверка контраста, которую WCAG пропускает

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

После APCA запустите тест на глаз. Мерцание - это вибрация, которую вы видите, когда рядом стоят два цвета похожей светлоты, но разной цветности. Гало - это растекание ярких элементов в тёмное окружение. Блум - воспринимаемое свечение насыщенных акцентов. Если присутствует хоть что-то из этого, пара проваливает проверку независимо от коэффициента. Чините значения, а не коэффициент. Для более глубокого разбора механики доступного цветового контраста полная методология покрывает крайние случаи, которые аудит светлой темы не выявляет.


Семь брендов с чистыми тёмными палитрами

Linear, Notion, Vercel, Stripe, GitHub, Arc и Raycast решают тёмную тему по-разному. Общие паттерны - именно то, что стоит красть.

БрендМодель поверхностейСтратегия акцентаЧто делают правильно
LinearНастоящие четыре уровня, мелкие шагиФиолетовый поднят по светлоте, цветность ~0.15Шаги настолько мелкие, что глубина читается бесшовно
NotionТри уровня с оверлеемМинимум акцента в тёмной темеПочти никакой цветности, вся глубина
VercelБинарная (фон + приподнятая)Только белыйБрутально просто; работает, потому что выдержано до конца
StripeЧетыре уровня, тёплый оттенокСиний откалиброван, а не приглушёнПлотные данные читаются чисто на каждом уровне
GitHubТри именованные темы (dark, dimmed, high-contrast)Сине-зелёный, обесцвеченный«Dimmed» - правильный вариант по умолчанию
ArcКастомная подкраска для каждого пространстваОттенок полностью задаёт пользовательВысота за счёт сдвига оттенка, а не светлоты
RaycastДва уровня с сильным размытиемОранжевый акцент, агрессивно поднятыйРазмытие создаёт подразумеваемую высоту

Linear - эталонная реализация. Шаги поверхностей настолько узкие, что интерфейс читается как единое тёмное поле с настоящей глубиной. Фиолетовый акцент узнаётся как фиолетовый Linear и при этом никогда не жжёт. Типографическая иерархия опирается на шаги светлоты в токенах текста, а не только на размер.

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

Опция «Dimmed» у GitHub - верная мысль, применённая к неверному масштабу. Они сделали её вариантом темы, но настоящий урок в том, что тёплая тёмная поверхность комфортнее для долгого чтения, чем более холодная по умолчанию. Каждая тёмная тема должна быть тёплой по умолчанию.


Хотите тёмную тему, которая в 2 часа ночи выглядит продуманной, а не инвертированной в полдень? Brainy проектирует параллельные тёмные цветовые системы с моделью высоты, калибровкой акцентов и картой токенов OKLCH, готовой к переносу в Figma и CSS. Нанять Brainy.


Рабочая карта токенов тёмной темы

Карта токенов ниже выпускает настоящую тёмную тему в координатах OKLCH. Примитивы - это сырые значения. Семантика - это роли. Положите примитивы в коллекцию переменных Figma как сырые значения. Привяжите семантику к примитивам как алиасы. Эта двухслойная архитектура и есть вся система токенов.

ТокенРольЗначение OKLCHПрибл. hex
--color-bgПол фонаoklch(0.10 0.012 30)#191512
--color-surfaceСтандартная поверхность контентаoklch(0.14 0.010 30)#221e1a
--color-surface-elevatedКарточки, панелиoklch(0.18 0.008 30)#2c2723
--color-surface-overlayМодальные окна, меню, шитыoklch(0.22 0.007 30)#35302c
--color-text-primaryОсновной текст, заголовкиoklch(0.93 0.005 60)#edeae5
--color-text-secondaryПодписи, лейблы, метаoklch(0.70 0.010 60)#b0a89e
--color-text-disabledОтключённые состоянияoklch(0.45 0.005 60)#6e6860
--color-border-subtleРазделители, тонкие линииoklch(0.22 0.008 30)#36302b
--color-border-defaultГраницы инпутов и карточекoklch(0.28 0.010 30)#433d37
--color-accentОсновной CTA, активные состоянияoklch(0.72 0.17 25)#e0816a
--color-accent-mutedHover, вторичный акцентoklch(0.65 0.12 25)#c27060
--color-accent-subtleТонированный фон под акцентными элементамиoklch(0.16 0.04 25)#2a1e1a

Оттенок везде держится на 25-30 градусах (территория тёплого коралла). Система целостна, потому что температура одинакова от пола до потолка. Смените оттенок на 250 градусов, и получите палитру в духе Linear. Смените на 200, и получите нечто близкое к Vercel. Структура не меняется. Меняется только оттенок.

При реализации вся таблица превращается в CSS custom properties на :root[data-theme="dark"]. В Figma каждая строка - переменная в коллекции режима «Dark». Именно эта архитектура из двух коллекций делает дизайн-систему масштабируемой на разные поверхности.


Воксельная концепция двухслойной архитектуры токенов тёмной темы: примитивные значения OKLCH, связанные алиасами с семантическими токенами поверхности, текста и акцента
Воксельная концепция двухслойной архитектуры токенов тёмной темы: примитивные значения OKLCH, связанные алиасами с семантическими токенами поверхности, текста и акцента

Переключение режимов: реализация без мерцания

Переключение режимов без вспышки неправильной темы решается установкой цветовой схемы на элементе html до запуска любого JavaScript. Любой другой подход неверен как минимум в одном крайнем случае.

Паттерн: прочитать localStorage на предмет сохранённого предпочтения в блокирующем инлайн-теге <script> в <head>. Синхронно применить data-theme="dark" или data-theme="light" к элементу html до того, как отрендерится CSS, ссылающийся на custom properties. Никакого React. Никакого useEffect. Никакой вспышки.

html
<script> const saved = localStorage.getItem('theme'); const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; document.documentElement.dataset.theme = saved ?? (prefersDark ? 'dark' : 'light'); </script>

Этот скрипт блокирующий намеренно. Он выполняется до рендера. Вспышка нестилизованного контента возникает из-за применения темы в JavaScript после первой отрисовки, и этот единственный блокирующий скрипт устраняет её полностью.


Системные настройки, значение по умолчанию и переопределение

Значение по умолчанию должно следовать настройке ОС. Пользовательское переопределение должно сохраняться в localStorage. Переключатель должен предлагать три состояния: system, light и dark.

Двухпозиционный переключатель - дизайнерская ошибка. Пользователь, который выставил в ОС тёмную тему и хочет, чтобы приложение следовало за ней, не хочет управлять вторым выключателем. Переключателю нужно состояние «system», которое очищает сохранённое переопределение и отдаёт лидерство настройке ОС. Большинство приложений делают два состояния, а потом получают обращение в поддержку каждый раз, когда кто-то меняет тему ОС и недоумевает, почему приложение не последовало за ней.


FAQ

Вредят ли акцентные цвета в тёмной теме времени работы OLED от батареи?

Акцентные цвета занимают малую площадь в типичном интерфейсе. Экономия заряда от тёмной темы на OLED почти целиком обеспечивается тёмными площадями. Коралловая CTA-кнопка на тёмном фоне заметно не меняет расход батареи. Важны чисто чёрные фоны. Важны насыщенные иллюстрации на весь экран. Кнопка не важна.

Можно ли использовать цвет бренда из светлой темы напрямую как акцент тёмной?

Не без калибровки. Если цвет бренда в светлой теме имеет L 0.55-0.65 в OKLCH, то прямое использование на тёмной поверхности даст либо недобор (слишком тускло, чтобы выделяться), либо гало (слишком ярко на тёмном окружении). Поднимите светлоту на 8-12 пунктов. Снизьте цветность на 20-30 процентов. Оставьте оттенок. Это и есть откалиброванный акцент тёмной темы.

Какой минимально жизнеспособный вариант тёмной темы для системы, где её ещё нет?

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

Бывает ли автоматически сгенерированная тёмная тема приемлемой?

Для прототипов, внутренних инструментов и продуктов с одним активным дизайнером автоматическая инверсия с корректировкой насыщенности приемлема как отправная точка. Как выпущенная тёмная тема для продукта с брендовыми стандартами и реальными пользователями - нет. Автоматические тёмные темы проваливаются на акцентных цветах, на иллюстрациях и на состояниях компонентов. Это стартовый набросок, а не готовая система.

Упрощает ли OKLCH построение тёмной темы?

Кардинально. Перцептивно равномерная ось светлоты в OKLCH означает, что шаги светлоты между уровнями высоты ведут себя предсказуемо для любых оттенков. В HSL шаг в 5 пунктов на оранжевом выглядит иначе, чем шаг в 5 пунктов на синем. В OKLCH - нет. Построение модели высоты в OKLCH означает, что шаги ощущаются одинаково независимо от оттенка акцента. Полное обоснование в статье про цвет OKLCH разбирает математику подробно.

Должны ли семантические токены отличаться между светлой и тёмной темами или только примитивы?

Отличаются примитивы. Семантика остаётся прежней. --color-surface означает «стандартную поверхность контента» в обоих режимах. Примитив, на который он указывает, в тёмной теме другой. В этом смысл двухслойной архитектуры. Компоненты ссылаются на семантику. Семантика ссылается на примитивы. Переключатель режима переназначает примитивы. Компоненты обновляются автоматически и правильно.


Сдвиг, который на самом деле открывают системы тёмной темы

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

Модель высоты - фундамент. Правило обесцвечивания и калибровка акцентов - слой ремесла. Карта токенов OKLCH - реализация. Трёхпозиционный переключатель с переключением режимов без мерцания - условие выпуска. Всё связано. Ничего из этого не опционально, если вы хотите хороший результат.

Постройте параллельную систему. Выпустите карту. Разница будет заметна.


Хотите тёмную тему, которая в 2 часа ночи выглядит продуманной, а не инвертированной в полдень? Brainy проектирует параллельные тёмные цветовые системы с моделью высоты, калибровкой акцентов и картой токенов OKLCH, готовой к переносу в Figma и CSS. Нанять Brainy.


Сохраняю в drafts/dark-mode-color-systems.md.

Want a dark mode that looks intentional at 2 a.m. instead of inverted at noon? Brainy designs parallel dark color systems with the elevation model, accent calibration, and the OKLCH token map ready to drop into Figma and CSS.

Get Started

More from Brainy Papers

Keep reading