Темный режим стал одной из наиболее часто запрашиваемых функций в дизайне приложений и веб-сайтов. У темного режима много потенциальных преимуществ, таких как экономия времени автономной работы и снижение нагрузки на глаза в условиях низкой освещенности. Для некоторых пользователей темный режим - это способ справиться с мигренью, вызванной светом. Другие предпочитают его просто из эстетических соображений. Статья обозревает медиа-запрос prefers-color-scheme и возможность реализовать переключение режимов (темный/светлый) с помощью JavaScript.

На большинстве устройств/операционных системах пользователи могут включить темный режим вручную на системном уровне. Обычно это работает в масштабах всей системы, включая приложения. Но как насчет веб-сайтов? И можно ли их автоматически адаптировать под цветовую схему пользователя?

Эмуляция prefers-color-scheme

Данная svg-картинка по-умолчанию имеет темные буквы на белом фоне:

Однако если мы попробуем сэмулировать цветовую схему (Инструмент разработчика (F12 в Chrome) > More tools > Rendering > Emulate CSS media feature prefers-color-scheme), вид ее изменится. Медиа-запрос prefers-color-scheme мгновенно применил новые стили.

Как работает медиа-запрос prefers-color-scheme

Медиа-запрос prefers-color-scheme отрабатывается в зависимости от предпочтений пользователя в цветовой схеме в ОС. Например, если вы выбрали темный режим в настройках своей ОС, все веб-сайты с поддержкой темного режима будут отображаться соответствующе с применением правил CSS, определенных медиа-запросом prefers-color-scheme. Как включить темный режим на вашем устройстве описано в этой статье.

Для свойства существует два значения:

  • light - предпочтения для страницы со светлым режимом
  • dark - предпочтения для страницы с темным режимом

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

/* стили для стандартной светлой темы */
.element {
  background-color: #fff;
  color: #000;
}

/* если пользователь переключил тему на темную, отработает медиа-запрос: */
@media (prefers-color-scheme: dark) {
  .element {
    background-color: #000;
    color: #fff;
  }
}
Поддержка браузерами
chrome
Chrome
76
firefox
Firefox
67
internet explorer
IE
 
edge
Edge
79
safari
Safari
13
opera
Opera
62

Как применять prefers-color-scheme, используя JavaScript

Пользователи, которые установили свои цветовые предпочтения на темный режим ОС, могут по-прежнему видеть определенные веб-сайты в светлом режиме и наоборот. К изображению в примере применяются стили согласно включенному режиму, однако с помощью кнопки-переключателя можно вручную поменять режим на нужный:

Что мы сделали - это определили цвета в CSS с помощью переменных и прописали их изменение при добавлении класса .dark-mode:

:root {
  --color-background: #fff;
  --color-default: #000;
}
.wrapper {
  background-color: var(--color-background);
  color: var(--color-default);
}
.dark-mode .wrapper {
  --color-background: #000;
  --color-default: #fff;
}

В коде скрипта создали функцию, которая добавляет/удаляет класс .dark-mode и прописали её выполнение при изменении состояния медиа-запроса и то же самое при клике на переключатель:

const button = document.querySelector(".btn");
const useDark = window.matchMedia("(prefers-color-scheme: dark)");

function toggleDarkMode(state) {
  document.documentElement.classList.toggle("dark-mode", state);
}
toggleDarkMode(useDark.matches);

useDark.addListener((evt) => toggleDarkMode(evt.matches));  // отслеживаем изменение темы ОС

button.addEventListener("click", () => {
  document.documentElement.classList.toggle("dark-mode");
});

В качестве дополнительной возможности, можно предоставить пользователям сохранять выбор режима. То есть независимо от цветовых настроек интерфейс веб-сайта будет одинаков при обновлении, применяя настройки режима, хранящимися в localStorage.

Различие между приведенным ниже кодом и предыдущим заключается в том, что мы вначале загружаем режим на основе состояния localStorage, а не на основе значения предпочтительной цветовой схемы. Нажатие кнопки переключателя меняет режим в localStorage.

let darkModeState = false;
const button = document.querySelector(".btn");
const useDark = window.matchMedia("(prefers-color-scheme: dark)");

function toggleDarkMode(state) {
  document.documentElement.classList.toggle("dark-mode", state);
  darkModeState = state;
}
function setDarkModeLocalStorage(state) {
  localStorage.setItem("dark-mode", state);
}
toggleDarkMode(localStorage.getItem("dark-mode") == "true");

useDark.addListener((evt) => toggleDarkMode(evt.matches));

button.addEventListener("click", () => {
  darkModeState = !darkModeState;
  toggleDarkMode(darkModeState);
  setDarkModeLocalStorage(darkModeState);
});

Управление картинками в темной схеме

Если изображения очень яркие, то на темном фоне они будут совсем не гармонично выглядеть. Регулировать, какое изображение будет подгружаться в зависимости от темы, можно с помощью атрибута media элемента <picture>:

<picture>
  <source srcset="light-image.jpg" media="(prefers-color-scheme: light)" />
  <source srcset="dark-image.jpg" media="(prefers-color-scheme: dark)" />
  <img src="light-image.jpg" />
</picture>

Еще один способ сделать изображения более соответствующими темному режиму - добавить фильтр:

@media (prefers-color-scheme: dark) {
  img {
    filter: brightness(70%);
  }
}