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

Цветовые системы тёмной темы: как собрать палитру, которая работает в 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-muted | Hover, вторичный акцент | 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». Именно эта архитектура из двух коллекций делает дизайн-систему масштабируемой на разные поверхности.

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




