Как нативно реализовать светлую и темную тему в CSS
Что проверяют
Знаете ли вы современные средства CSS для тем, а не только переключение классов из JavaScript. Следом обычно спрашивают, как уважать системную настройку и при этом дать пользователю выбрать тему вручную без мигания при загрузке.
Как отвечать
Основа это цвета в пользовательских свойствах: --bg, --text, --accent на :root, а компоненты пользуются только ими. Дальше нативные механизмы:
prefers-color-scheme: медиа-запрос@media (prefers-color-scheme: dark)переопределяет переменные по системной теме без единой строки JavaScript;color-scheme: свойствоcolor-scheme: light darkна:rootили<meta name="color-scheme" content="light dark">сообщает браузеру, что страница поддерживает обе темы. Тогда поля форм, скроллбары и фон по умолчанию тоже перекрашиваются;light-dark(): запись видаcolor: light-dark(#111, #eee)выбирает значение по действующемуcolor-scheme. Функция уже входит в Baseline, для старых браузеров нужен запасной вариант;- ручной выбор: атрибут
data-themeна<html>, под ним задаётсяcolor-scheme: darkилиlight, иlight-dark()послушно переключается. Без JavaScript переключатель можно сделать через чекбокс и:root:has(#theme:checked), но запомнить выбор всё равно придётся скриптом вlocalStorage; - картинки:
<picture>с<source media="(prefers-color-scheme: dark)">, а иконки в SVG черезcurrentColor.
Хорошее решение поддерживает три состояния: светлая, тёмная и «как в системе». За сменой системной темы следят через matchMedia('(prefers-color-scheme: dark)') и событие change.
Где спотыкаются
Применяют сохранённую тему скриптом в конце страницы. Пользователь видит вспышку светлой темы, поэтому выбор темы делают маленьким инлайн-скриптом в <head> до первой отрисовки.
Забывают про color-scheme. Страница тёмная, а поля ввода и полосы прокрутки остаются белыми.
Инвертируют цвета механически. Чисто чёрный фон с белым текстом режет глаза, тени на тёмном фоне не видны, а контраст всё равно надо проверять по WCAG: не ниже 4.5:1 для обычного текста.