Как определить предпочтительную цветовую схему пользователя в JavaScript
В последних версиях macOS (Mojave) и Windows 10 пользователи смогли включить темный режим на уровне системы. Это хорошо работает и легко обнаруживается для собственных приложений.
Веб-сайты были странными приложениями, где издатель веб-сайта должен решить, какую цветовую схему должны использовать пользователи. Некоторые сайты предлагают поддержку тем. Чтобы пользователи могли переключаться, им нужно найти конфигурацию и вручную обновить настройки для каждого отдельного веб-сайта.
Возможно ли, чтобы это обнаружение было выполнено автоматически и веб-сайты представляли тему, которая учитывает предпочтения пользователя?
CSS media query prefers-color-scheme
draft
Существует черновая спецификация CSS для медиазапросов, где указана prefers-color-scheme. Он предназначен для определения того, запросил ли пользователь систему использовать тему светлого или темного цвета.
Это похоже на то, с чем мы можем работать! Мы должны быть в курсе любых изменений в черновике, поскольку он может измениться в любое время, так как это всего лишь ... черновик. Запрос prefers-color-scheme
может иметь три различных значения: light
, dark
, и no-preference
.
Поддержка веб-браузерами по состоянию на сентябрь 2019 г.
https://caniuse.com/#search=prefers-color-scheme.
Почему только определение CSS недостаточно
Обычный подход, который я видел до сих пор, состоит в том, чтобы использовать только CSS-подход и переопределять CSS-правила для определенных классов при совпадении медиа-запроса. Что-то вроде этого:
/* global.css */ .themed { display: block; width: 10em; height: 10em; background: black; color: white; } @media (prefers-color-scheme: light) { .themed { background: white; color: black; } }
Поскольку это хорошо работает для многих случаев использования, существуют методы стилей, которые не используют CSS таким образом. Если для темы используются, например, styled-components, то при смене темы объект JS заменяется.
Доступ к предпочтительной схеме также полезен для аналитики и более предсказуемых переопределений CSS, а также для более детального контроля над тем, какие элементы должны быть тематическими, а какие нет.
Начальный подход в JS
В прошлом я узнал, что вы можете обнаруживать медиа-запросы, устанавливая значение CSS content
для элемента, если медиа-запрос совпадает. Это определенно хак, но это работает!
Поэтому, когда пользователь загружает CSS и медиа-запрос совпадает с одной из вышеуказанных цветовых схем, значение свойства content
у html
элемента устанавливается на «light» или «dark».
Тогда возникает вопрос: как мы читаем значение content
в элементе html
?
Мы можем использовать window.getComputedStyle, например так:
window.getComputedStyle(document.body.parentElement).content
И это прекрасно работает! Этот подход подходит для однократного чтения, но он не реагирует и автоматически обновляется, когда пользователь меняет цветовую схему своей системы. Чтобы быть обновленным, требуется перезагрузка страницы (или выполнить чтение выше с интервалом).
Реактивный подход JS
Как мы можем узнать, когда пользователь меняет цветовую схему системы? Есть ли какие-нибудь события, которые мы можем слушать?
Да это так!
Существует window.matchMedia, доступный в современных веб-браузерах .
Что здорово в matchMedia
так это то, что мы можем подключить к нему слушателя, который будет вызываться каждый раз, когда изменяются настройки медиазапросов.
Слушатель будет вызываться с объектом, содержащим информацию, если медиа-запрос начал сопоставление или прекратил сопоставление. С помощью этой информации мы можем вообще пропустить CSS и просто работать с JS.
Этот подход действительно хорошо работает в поддерживаемых веб-браузерах и просто отключается, если window.matchMedia
не поддерживается.