В последних версиях macOS (Mojave) и Windows 10 пользователи смогли включить темный режим на системном уровне. Это хорошо работает, и его легко обнаружить для собственных приложений.
Веб-сайты были странными приложениями, где издатель веб-сайта сам решал, какую цветовую схему использовать. Некоторые веб-сайты предлагают поддержку тем. Чтобы пользователи могли переключиться, они должны найти конфигурацию для этого и вручную обновить настройки для каждого отдельного веб-сайта.
Возможно ли, чтобы это обнаружение выполнялось автоматически и на веб-сайтах отображалась тема, учитывающая предпочтения пользователя?
Медиа-запрос CSS ‘prefers-color-scheme'
draft
Есть черновик медиазапросов CSS уровня 5, где указано prefers-color-scheme. Он предназначен для определения того, запросил ли пользователь систему использовать светлую или темную цветовую тему.
Это похоже на то, с чем мы можем работать! Однако нам нужно быть в курсе любых изменений в черновике, так как он может измениться в любой момент, поскольку это всего лишь ... черновик. Запрос prefers-color-scheme
может иметь три разных значения: light
, dark
и no-preference
.
Поддержка веб-браузера с марта 2019 г.
Текущая поддержка браузера очень ограничена, и она недоступна ни в одном из стабильных выпусков каких-либо поставщиков. Мы можем наслаждаться этим только в Safari Technology Preview версии 12.1 и в Firefox 67.0a1. Что замечательно, так это то, что есть двоичные файлы, которые его поддерживают, поэтому мы можем работать с ним и опробовать его в веб-браузерах. Чтобы узнать о текущей поддержке браузера, посетите 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
устанавливается на «светлый» или «темный».
Тогда возникает вопрос, как нам прочитать значение content
элемента html
?
Мы можем использовать window.getComputedStyle, например:
И это прекрасно работает! Этот подход подходит для одноразового чтения, но он не является реактивным и автоматически обновляется, когда пользователь меняет цветовую схему системы. Для обновления требуется перезагрузка страницы (или выполнение вышеуказанного чтения с интервалом).
Реактивный подход JS
Как мы можем узнать, когда пользователь меняет цветовую схему системы? Есть ли какие-нибудь события, которые мы можем слушать?
Да это так!
В современных веб-браузерах есть window.matchMedia.
Что замечательно в matchMedia
, так это то, что мы можем прикрепить к нему слушателя, который будет вызываться в любое время, когда совпадение изменится.
Слушатель будет вызван с объектом, содержащим информацию, если медиа-запрос начал сопоставление или прекратил сопоставление. Имея эту информацию, мы можем полностью пропустить CSS и просто работать с JS.
Этот подход очень хорошо работает в поддерживаемых веб-браузерах и просто отключается, если window.matchMedia
не поддерживается.
Реагировать на крючок
Поскольку мы используем React в neo4j-browser, я написал это как собственный перехватчик React, чтобы упростить повторное использование во всех наших приложениях и вписаться в систему React.
Это немного больше кода, чем в первом коротком доказательстве концепции. У нас улучшено обнаружение ошибок, и мы также удаляем прослушиватели событий, когда перехватчик размонтируется.
В нашем случае пользователи могут выбрать замену автоматически определяемой схемы чем-то другим (например, мы предлагаем выделенную тему, часто используемую при проведении презентаций).
А затем используйте его так на уровне приложения:
Последняя часть зависит от того, как тематика сделана в вашем приложении. В приведенном выше примере объект данных темы передается поставщику контекста, который делает этот объект доступным во всем приложении React.
Конечный результат
Вот гифка с конечным результатом, и, как видите, он мгновенный.
Последние мысли
Это был забавный эксперимент, сделанный во время так называемого лабораторного дня, который мы проводим в команде UX в Neo4j. Ранние стадии спецификации и (следовательно) отсутствие поддержки браузеров еще не оправдывают превращение этого в какой-либо продукт. Но поддержка может прийти раньше, чем позже.
Кроме того, мы поставляем некоторые продукты на базе Electron, и там есть electron.systemPreferences.isDarkMode()
...
Об авторе
Оскар Хейн - руководитель группы / старший инженер в Neo4j.
Он работает над несколькими приложениями для конечных пользователей и библиотеками кода Neo4j: s, а также является автором двух технических книг.
Следуйте за Оскаром в Twitter: @oskarhane