CSS-функция light-dark(): нативное переключение тем
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://colorfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://colorfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://colorfyi.com/entity//)
Use the native HTML custom element.
Реализация тёмного режима исторически требовала немалого шаблонного кода: медиазапрос prefers-color-scheme, переопределяющий каждую кастомную переменную, JavaScript для пользовательского переключения, localStorage для сохранения предпочтений и встроенный скрипт в <head> для предотвращения мигания неверной темы при загрузке страницы. CSS-функция light-dark() не устраняет всё это, но значительно сокращает объём CSS для решения этой задачи.
light-dark() — CSS-функция для работы с цветом, которая принимает ровно два значения и возвращает первое, когда активная цветовая схема светлая, или второе, когда тёмная. Это семантический CSS-эквивалент тернарного оператора для цветов.
Что такое light-dark()?
Сигнатура функции проста:
color: light-dark(<light-color>, <dark-color>);
Когда активная цветовая схема светлая, браузер использует <light-color>. Когда тёмная — <dark-color>. «Активная цветовая схема» определяется CSS-свойством color-scheme, которое, в свою очередь, реагирует на системный медиазапрос prefers-color-scheme или явное значение, заданное для элемента.
Функция поддерживается в:
- Chrome/Edge: с версии 123 (март 2024)
- Firefox: с версии 120 (ноябрь 2023)
- Safari: с версии 17.5 (июнь 2024)
Глобальная поддержка составляет около 85% по состоянию на начало 2026 года. Это относительно новое дополнение, но покрытие браузерами растёт достаточно быстро для использования в production с резервной стратегией.
Как это работает со свойством color-scheme
light-dark() не работает изолированно. Она полностью зависит от правильной установки CSS-свойства color-scheme. Без него функция не имеет контекста для определения возвращаемого значения.
Свойство color-scheme объявляет, какие цветовые схемы поддерживает документ или элемент. Установка его на :root — отправная точка:
:root {
color-scheme: light dark;
}
Это единственное объявление сообщает браузеру, что ваша страница поддерживает обе схемы. Затем браузер:
- Считывает системное предпочтение пользователя
prefers-color-scheme - Применяет соответствующую схему
- Заставляет все вызовы
light-dark()на странице разрешаться в подходящее значение
После этого определение цветов, адаптированных к теме, сводится к написанию одиночных объявлений:
:root {
color-scheme: light dark;
--color-background: light-dark(#FFFFFF, #0F0F17);
--color-text: light-dark(#1A1A2E, #E8E8F0);
--color-border: light-dark(#DEE2E6, #2E2E4A);
--color-accent: light-dark(#2563EB, #60A5FA);
}
Никакого медиазапроса. Никаких переопределений в селекторах. Одно объявление на цвет, оба значения в одной строке. Браузер обрабатывает переключение автоматически на основе системных предпочтений.
Ограничение одной схемой
Установка color-scheme: light или color-scheme: dark принудительно задаёт одну схему независимо от системных предпочтений:
/* Всегда светлый, независимо от настроек ОС */
.widget {
color-scheme: light;
background: light-dark(#FFFFFF, #0F0F17);
/* Всегда разрешается в #FFFFFF */
}
/* Всегда тёмный */
.dark-panel {
color-scheme: dark;
color: light-dark(#1A1A2E, #E8E8F0);
/* Всегда разрешается в #E8E8F0 */
}
Это полезно для компонентов интерфейса, которые всегда должны отображаться в определённом режиме — например, редактор кода, который всегда должен иметь тёмный фон независимо от темы страницы.
Ключевое слово only
Добавление only предотвращает переопределение схемы каскадом для данного элемента:
.forced-light {
color-scheme: only light;
}
Это прежде всего полезно, когда есть элемент внутри тёмного контекста, который должен оставаться светлым.
Замена медиазапросов prefers-color-scheme
Традиционный подход к тёмному режиму с медиазапросами требует дублирования или переопределения каждой цветовой переменной:
/* Традиционный подход — многословный */
:root {
--bg: #FFFFFF;
--text: #1A1A2E;
--accent: #2563EB;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0F0F17;
--text: #E8E8F0;
--accent: #60A5FA;
}
}
С light-dark() это сворачивается в:
/* Подход light-dark() — одно объявление на переменную */
:root {
color-scheme: light dark;
--bg: light-dark(#FFFFFF, #0F0F17);
--text: light-dark(#1A1A2E, #E8E8F0);
--accent: light-dark(#2563EB, #60A5FA);
}
Сами переменные становятся самодокументирующими. Читая --accent: light-dark(#2563EB, #60A5FA), вы сразу видите оба значения и понимаете их взаимосвязь. Подход с медиазапросом разбрасывает значения светлого и тёмного режима по двум отдельным блокам, что затрудняет аудит и обновление палитры.
Когда медиазапросы ещё нужны
Медиазапрос prefers-color-scheme остаётся необходимым для нецветовых адаптаций, меняющихся в зависимости от темы:
@media (prefers-color-scheme: dark) {
/* Нецветовые корректировки, которые light-dark() не может выразить */
img.logo {
filter: invert(1) brightness(1.2);
}
.hero-image {
opacity: 0.85;
}
}
Для всего, что является исключительно изменением цвета, light-dark() чище. Для структурных или нецветовых адаптаций (фильтры изображений, непрозрачность, свойства отображения) медиазапрос остаётся правильным инструментом.
Совместное использование с CSS-кастомными свойствами
light-dark() работает внутри значений кастомных свойств — именно здесь раскрывается его полная мощь. Вы определяете все цвета с поддержкой тем в :root, и каждый компонент на странице ссылается на эти переменные. При смене цветовой схемы всё обновляется одновременно.
Пример полной системы тем
:root {
color-scheme: light dark;
/* Фоны */
--color-bg-base: light-dark(#FFFFFF, #0F0F17);
--color-bg-elevated: light-dark(#F8F9FA, #1A1A2E);
--color-bg-overlay: light-dark(#F1F3F5, #252540);
/* Текст */
--color-text-primary: light-dark(#1A1A2E, #E8E8F0);
--color-text-secondary: light-dark(#4A4A6A, #A8A8C0);
--color-text-muted: light-dark(#6C757D, #6A6A88);
--color-text-inverse: light-dark(#FFFFFF, #1A1A2E);
/* Рамки */
--color-border: light-dark(#DEE2E6, #2E2E4A);
--color-border-strong: light-dark(#ADB5BD, #4A4A6A);
/* Интерактивные / бренд */
--color-accent: light-dark(#2563EB, #60A5FA);
--color-accent-hover: light-dark(#1D4ED8, #93C5FD);
--color-accent-subtle: light-dark(#DBEAFE, #1E3A5F);
/* Обратная связь */
--color-success: light-dark(#16A34A, #4ADE80);
--color-warning: light-dark(#D97706, #FCD34D);
--color-danger: light-dark(#DC2626, #F87171);
--color-success-bg: light-dark(#F0FDF4, #052E16);
--color-warning-bg: light-dark(#FFFBEB, #2D1A00);
--color-danger-bg: light-dark(#FEF2F2, #2D0A0A);
}
Компоненты ссылаются на эти переменные, не зная ничего о темизации:
.card {
background: var(--color-bg-elevated);
border: 1px solid var(--color-border);
color: var(--color-text-primary);
}
.btn-primary {
background: var(--color-accent);
color: var(--color-text-inverse);
}
.btn-primary:hover {
background: var(--color-accent-hover);
}
.alert-success {
background: var(--color-success-bg);
color: var(--color-success);
border-left: 3px solid var(--color-success);
}
Обратите внимание: светлый акцент #2563EB в тёмном режиме меняется на #60A5FA. Это намеренно: синий 600-го оттенка проходит WCAG AA по контрасту с белым, но не с тёмным фоном. Синий 400-го оттенка достаточно светлый для достижения необходимого контраста на тёмных поверхностях. Используйте Проверщик контраста для верификации комбинаций и Генератор оттенков для подбора правильного оттенка в каждом режиме.
Вложение light-dark() в другие функции
light-dark() возвращает цветовое значение, поэтому его можно использовать везде, где допустим цвет, — в том числе внутри других функций:
:root {
color-scheme: light dark;
--brand: #3B82F6;
/* light-dark() внутри color-mix() */
--brand-surface: color-mix(
in oklch,
var(--brand) 15%,
light-dark(white, #09090b)
);
}
Это создаёт цвет поверхности — 15% тинт фирменного цвета, смешанный с белым в светлом режиме и почти-чёрным в тёмном, — автоматически адаптированный к теме.
Добавление пользовательского переключения (JavaScript)
Реакция на системные предпочтения — правильный вариант по умолчанию, но пользователи должны иметь возможность переключаться самостоятельно. Для этого нужен JavaScript для сохранения выбора и переопределения браузерного значения по умолчанию.
Управление color-scheme через JavaScript
Ключевой момент: color-scheme — CSS-свойство, которое можно задать через JavaScript:
// Программно установить цветовую схему
document.documentElement.style.colorScheme = 'dark';
document.documentElement.style.colorScheme = 'light';
// Убрать переопределение (возврат к системным предпочтениям)
document.documentElement.style.colorScheme = '';
Когда color-scheme задаётся через inline-стиль на корневом элементе, он переопределяет объявление в таблице стилей. Все значения light-dark() разрешаются в подходящий вариант заново.
Полная реализация переключения
const STORAGE_KEY = 'color-scheme-preference';
function initColorScheme() {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored === 'light' || stored === 'dark') {
document.documentElement.style.colorScheme = stored;
}
// Если предпочтения не сохранены, CSS color-scheme: light dark; обрабатывает это через предпочтение ОС
}
function toggleColorScheme() {
const current = getComputedStyle(document.documentElement)
.colorScheme
.trim();
// Определить следующее значение
const next = current.includes('dark') ? 'light' : 'dark';
document.documentElement.style.colorScheme = next;
localStorage.setItem(STORAGE_KEY, next);
// Обновить состояние кнопки переключения
updateToggleButton(next);
}
function updateToggleButton(scheme) {
const btn = document.getElementById('theme-toggle');
if (!btn) return;
btn.setAttribute('aria-label',
scheme === 'dark' ? 'Переключить на светлый режим' : 'Переключить на тёмный режим'
);
btn.dataset.scheme = scheme;
}
// Запустить до первой отрисовки, чтобы избежать мигания
initColorScheme();
// Привязать к кнопке переключения после готовности DOM
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('theme-toggle')
?.addEventListener('click', toggleColorScheme);
});
Вызов initColorScheme() до полного разбора DOM критически важен. Если выполнить позже, пользователи с сохранёнными предпочтениями увидят кратковременную тему по умолчанию до переключения — классическое «мигание неправильной темы». Размещайте этот скрипт inline в <head> или осторожно используйте атрибут defer (скрипты с defer выполняются после разбора DOM, что может быть слишком поздно).
Паттерн предотвращения мигания
Наиболее надёжный подход запускает минимальный inline-скрипт в <head>:
<head>
<meta name="color-scheme" content="light dark">
<script>
const stored = localStorage.getItem('color-scheme-preference');
if (stored) {
document.documentElement.style.colorScheme = stored;
}
</script>
<link rel="stylesheet" href="styles.css">
</head>
Этот скрипт выполняется синхронно до применения CSS, поэтому браузер вычисляет правильное значение color-scheme с первой отрисовки. Тег <meta name="color-scheme"> сообщает браузеру ожидаемые схемы ещё до разбора CSS — это предотвращает кратковременное белое мигание на страницах с тёмным режимом в некоторых браузерах.
Руководство по миграции с JS-базовых тем
Многие существующие реализации тёмного режима используют атрибут data-theme, переключаемый JavaScript, с CSS-переопределениями в области [data-theme="dark"]. Миграция на light-dark() выполняется постепенно — необязательно менять всё сразу.
Шаг 1: Добавьте color-scheme к :root
:root {
color-scheme: light dark;
/* Существующие кастомные свойства остаются без изменений */
}
Шаг 2: Мигрируйте переменные по одной
Начните с одной переменной как доказательства концепции. Замените паттерн с разделёнными объявлениями на унифицированный light-dark():
/* До */
:root {
--bg: #FFFFFF;
}
[data-theme="dark"] {
--bg: #0F0F17;
}
/* После */
:root {
color-scheme: light dark;
--bg: light-dark(#FFFFFF, #0F0F17);
}
Шаг 3: Обновите переключение
Измените JavaScript-переключение с установки data-theme на установку style.colorScheme:
/* До */
document.documentElement.setAttribute('data-theme', scheme);
/* После */
document.documentElement.style.colorScheme = scheme;
Шаг 4: Удалите селекторы data-theme
После миграции всех переменных удалите CSS-блоки [data-theme="dark"].
Резервный вариант для браузеров
Для примерно 15% браузеров без поддержки light-dark() предоставьте явные запасные варианты:
:root {
/* Запасной вариант: явные значения светлого режима */
--color-bg: #FFFFFF;
--color-text: #1A1A2E;
/* Прогрессивное улучшение с light-dark() */
--color-bg: light-dark(#FFFFFF, #0F0F17);
--color-text: light-dark(#1A1A2E, #E8E8F0);
}
/* Запасной тёмный режим для браузеров без light-dark() */
@supports not (color: light-dark(white, black)) {
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #0F0F17;
--color-text: #E8E8F0;
}
}
}
Блок @supports not (color: light-dark(white, black)) применяется только к браузерам, не понимающим light-dark(). Современные браузеры полностью игнорируют его, поскольку отрицательное условие ложно.
Ключевые выводы
light-dark(<light-value>, <dark-value>)возвращает первый аргумент в светлой цветовой схеме и второй в тёмной. Это нативный CSS-способ выразить «этот цвет, адаптированный к текущей теме».- Требует установки CSS-свойства
color-schemeна элементе (или предке). Всегда задавайтеcolor-scheme: light darkна:rootдля автоматической адаптации черезprefers-color-scheme. - Главное преимущество перед традиционным подходом с медиазапросами — размещение обоих значений темы в одном объявлении, делающее взаимосвязь светлого и тёмного вариантов явной и легко проверяемой.
- Пользовательское переключение требует установки
document.documentElement.style.colorSchemeчерез JavaScript. Сохраняйте выбор вlocalStorageи применяйте его в inline-скрипте<head>до загрузки CSS, чтобы предотвратить мигание. - Миграция с систем на базе атрибута
data-themeвыполняется постепенно: перемещайте переменные по одной из паттерна переопределения[data-theme="dark"]в паттернlight-dark(). - Поддержка браузерами составляет ~85% по состоянию на 2026 год. Используйте запасной вариант
@supports notс блоком@media (prefers-color-scheme: dark)для старых браузеров. - Используйте Проверщик контраста для верификации соответствия WCAG обоих цветовых значений в каждой паре
light-dark()и Генератор оттенков для подбора правильного оттенка в каждом режиме.
Похожие цвета
Похожие бренды
Похожие инструменты
Проверка контрастности
Проверяйте коэффициенты контрастности цветов в соответствии с рекомендациями WCAG 2.1. Тестируйте соответствие AA и AAA для обычного и крупного текста.
Генератор оттенков
Генерируйте шкалы оттенков в стиле Tailwind CSS (50–950) из любого базового цвета для дизайн-систем.