Современное динамическое темизирование компонентов с помощью функций CSS
Создание адаптивных и поддерживаемых дизайн-систем долгое время требовало от веб-разработчиков написания сложного кода. Глобальные темы (темная и светлая) реализовывались либо через дублирование стилей в медиа-запросах @media (prefers-color-scheme), либо с помощью JavaScript, который динамически переключал CSS-классы на корневом элементе страницы. Ситуация становилась еще сложнее, когда требовалось реализовать локальное темизирование — например, покрасить отдельную карточку в фирменные цвета бренда так, чтобы весь вложенный в нее текст автоматически адаптировал свой цвет для сохранения читаемости (контрастности).
Современный стандарт CSS предоставляет набор нативных инструментов, которые позволяют полностью разделить глобальное макро-темизирование (уровень всей страницы) и локальное микро-темизирование (уровень отдельных изолированных компонентов). Объединение четырех возможностей спецификации — @property (типизированные пользовательские свойства), light-dark() (функция выбора цвета на основе текущей цветовой схемы), contrast-color() (автоматический расчет контрастного цвета текста) и @container style() (контейнерные запросы по стилям) — позволяет верстать гибкие интерфейсы без единой строчки JavaScript.
Макро-темизирование с помощью функции light-dark()
Функция light-dark(color1, color2) возвращает первый цвет, если на элементе активна светлая цветовая схема (color-scheme: light), и второй цвет, если активна темная схема (color-scheme: dark).
Главное преимущество этого подхода перед традиционными медиа-запросами заключается в поддержке наследования. Вместо отслеживания системных настроек пользователя на глобальном уровне, функция light-dark() ориентируется на вычисленное браузером значение свойства color-scheme для конкретного элемента DOM-дерева.
Как настроить макро-темизирование страницы:
- Инициализация: Укажите на корневом элементе страницы (
htmlили:root) поддержку обеих схем. Это заставит браузер автоматически считывать системные предпочтения пользователя. - Переопределение: При необходимости принудительно включить темную тему для определенного блока страницы (например, боковой панели управления), просто задайте для него
color-scheme: dark. Все вложенные элементы автоматически переключат цвета своих функцийlight-dark(). - Объявление переменных: Создайте глобальные переменные для фонов и текста, используя новую функцию.
/* Базовая настройка темы в файле стилей */
:root {
color-scheme: light dark; /* Включает автоматическое переключение схем */
--bg-primary: light-dark(#ffffff, #121212);
--text-primary: light-dark(#212121, #eeeeee);
}
body {
background-color: var(--bg-primary);
color: var(--text-primary);
}
Подробные примеры работы и синтаксис функции описаны в справочном руководстве MDN на странице developer.mozilla.org.
Микро-темизирование: Управление контрастом с contrast-color()
На уровне компонентов часто возникает задача создания гибких карточек. Если у карточки динамически меняется фоновый цвет (например, задается администратором в панели управления), разработчик должен гарантировать, что текст поверх этого фона останется читаемым.
Для этого в CSS вводится функция contrast-color(color). Браузер автоматически вычисляет степень яркости переданного фонового цвета и подбирает для него максимально контрастный цвет текста (по умолчанию — черный или белый), удовлетворяющий стандартам доступности интерфейсов.
Инструкция по созданию адаптивного компонента:
- Задайте фоновый цвет компонента (это может быть бренд-цвет компании).
- Задайте цвет текста с помощью функции автоматического подбора.
- Важное ограничение: Браузер возвращает только чистый черный (
#000000) или чистый белый (#ffffff) цвет. Если дизайн-система требует использования мягких оттенков (например, кремового цвета на темном фоне), используйте результатыcontrast-color()как маркер (детектор) в контейнерных запросах.
/* Использование contrast-color в карточке */
.brand-card {
--card-bg: #e0f7fa; /* Динамический цвет фона */
background-color: var(--card-bg);
color: contrast-color(var(--card-bg)); /* Браузер сам выберет черный или белый */
}
Контейнерные запросы по стилям для мягкой темизации
Чтобы применить сложные цветовые палитры вместо контрастного черного/белого текста, используется механизм контейнерных запросов по стилям (@container style()). Описание принципов работы этой технологии доступно в блоге разработчиков Chrome на странице developer.chrome.com.
Для корректной работы запроса необходимо зарегистрировать типизированную переменную с помощью директивы @property. Это гарантирует, что браузер будет воспринимать значение цвета именно как цвет, а не как обычную текстовую строку, что важно для выполнения логических проверок.
Процедура настройки адаптивной палитры:
- Зарегистрируйте типизированное свойство
--contrast-colorв CSS-файле. - Задайте это свойство для компонента, используя результат функции автоподбора контраста.
- Опишите правила ветвления с помощью
@container style(): если вычисленное значение контрастного цвета является белым, значит, фон под ним достаточно темный — примените к тексту мягкий теплый оттенок. Если черным — примените глубокий темный тон.
/* Регистрация переменной */
@property --contrast-color {
syntax: '<color>';
inherits: true;
initial-value: black;
}
.brand-card {
--contrast-color: contrast-color(var(--card-bg));
container-type: normal;
}
/* Ветвление на основе вычисленного контраста */
@container style(--contrast-color: white) {
.brand-card .card-description {
color: oklch(0.95 0.02 80); /* Мягкий светлый оттенок для темного фона */
}
}
@container style(--contrast-color: black) {
.brand-card .card-description {
color: oklch(0.25 0.02 240); /* Глубокий темный оттенок для светлого фона */
}
}
Процесс верификации и тестирования темы
Для подтверждения качества и доступности созданной темы разработчику необходимо выполнить следующие действия:
- Проверка системного переключения: Переключите тему в настройках операционной системы (или с помощью эмуляции в панели разработчика DevTools). Убедитесь, что глобальный фон страницы адаптировался мгновенно и без задержек.
- Проверка локального переопределения: Убедитесь, что блоки с жестко заданной схемой
color-scheme: darkсохраняют темный вид даже при активной светлой теме ОС, а вложенный текст корректно наследует стили. - Стресс-тест контрастности: Сгенерируйте набор карточек с экстремальными фоновыми цветами (очень светлые, очень темные, пастельные, неоновые). Пройдите по ним визуально и с помощью автоматических плагинов проверки доступности (например, Lighthouse или Axe). Убедитесь, что коэффициент контрастности текста (Contrast Ratio) везде соответствует стандарту WCAG AA (не менее 4.5:1).
- Тестирование теней и свечений (Elevation): В светлой теме элементы должны выделяться с помощью теней (
box-shadow), цвет которых становится прозрачным в темной схеме. В темной теме для создания ощущения глубины используйте легкие светящиеся рамки, вычисляемые из цвета фона с помощью относительного синтаксиса цветов (oklch(from var(--bg) ...)). - Внимание к ограничениям: На момент подготовки статьи экспериментальная функция
@functionимеет крайне ограниченную поддержку в браузерах. Избегайте использования@functionдля построения критически важных элементов интерфейса без предоставления надежных резервных вариантов (fallbacks).

