Найти тему
Журнал «Код»

Тёмная тема на сайте: второй этап

Сохраняем тему и добавляем переключатель

В прошлой статье мы добавили поддержку тёмной темы на странице. Вот короткая версия:

  • тёмная тема — это когда фон делают тёмным, а текст светлым, чтобы было удобно читать в темноте;
  • браузеры умеют определять тёмную тему на устройстве и включать её на странице, если для этого на странице есть специальная настройка в CSS;
  • вместо автоматического включения можно добавить ручной переключатель.

В прошлый раз мы проверили, как работает автопереключение, потом убрали его и добавили ручной режим. Сегодня объединим эти два подхода, а заодно научим браузер сохранять наши настройки.

Добавляем автопереключатель на страницу

Добавим автопереключение тёмной темы на страницу следующим способом:

  1. Мы оставляем ручной выбор темы на случай, если пользователь захочет сам выбрать, что ему удобнее.
  2. Ниже добавляем переключатель авторежима тёмной темы — когда он включён, используются системные настройки.
  3. После включения авторежима ручной выбор будет недоступен — мы его скроем с экрана.
  4. После выключения ручной выбор снова становится доступен.

Чтобы не городить с нуля элементы интерфейса, мы позаимствуем готовые компоненты из фреймворка Bootstrap 5. Оттуда нам нужен переключатель-слайдер. Мы вставим его в HTML-страницу после абзаца с ручным переключением. Сразу добавим вызов функции autoDarkLight() при нажатии на переключатель:

-2

gist:c26c23e2698fd092a507cafb4f39e61c

Переключатель появился, но он пока ни на что не влияет
Переключатель появился, но он пока ни на что не влияет

Настраиваем авторежим

Мы уже выяснили, что для автоматического включения тёмной темы достаточно добавить в стили такой медиазапрос:

JavaScript
JavaScript

Нам нужно добавить это в стили при включении авторежима и убрать оттуда при его выключении. Чтобы получить доступ к таблице стилей, добавим в  самое начало скрипта dark.js такое:

// находим стили по тегу
const style = document.getElementsByTagName("style")[0];
// получаем доступ к разделу стилей
const styleSheet = style.sheet;

Теперь наша задача — написать функцию autoDarkLight() и добавить в неё всего одну проверку: нажат переключатель или нет. Если нажат — добавляем медиазапрос в стили, а если не нажат — убираем его оттуда.

Хитрость в том, что медиазапрос добавится в самый конец стилей, а значит, он применится самым последним. Получается, нам неважно, какие стили у страницы стояли до этого, — всё равно последним сработает наш автовыбор тёмной темы.

JavaScript
JavaScript

gist:ca1eccd13ad25ae965adb9d570f61cc5

Переключатель скрывает ручной выбор и добавляет поддержку выбранной темы устройства
Переключатель скрывает ручной выбор и добавляет поддержку выбранной темы устройства

Сохраняем настройки

Страница теперь умеет переключаться в тёмный режим и автоматически, и вручную, но при перезагрузке всё слетает — все режимы нужно заново включать самому.

Чтобы сайт запоминал, что мы сделали в настройках, используем локальное хранилище браузера (оно же localStorage). Логика будет такая:

  • При каждом переключении мы записываем в хранилище текущее значение переключателя. Если в памяти нет вообще никакого значения, значит, мы ещё не трогали этот переключатель.
  • Когда страница загрузилась, мы достаём из памяти по очереди значение каждого переключателя и применяем их на страницу.

Применяем — это значит, что мы виртуально нажимаем на переключатели, если они активны. Это позволяет сразу установить всё в то положение, которое было до перезагрузки. Читайте комментарии, чтобы разобраться в логике работы с хранилищем:

-7
gist:99b31911577a271f0d04e266d2105a01

Последнее, что нам осталось сделать, — сохранять в память текущее положение переключателей во время их изменения. Для этого добавим в самый конец функции darkLight () такую строку:

// сохраняем в памяти статус ручного переключателя
localStorage.setItem('selected',dark);

И то же самое сделаем в функции autoDarkLight () — добавим сохранение после установки видимости ручного переключателя:

localStorage.setItem('auto',true); ← если переключатель установлен;

localStorage.setItem('auto',false); ← если переключатель не установлен.

Результат

У нас получился красивый переключатель, который заставляет страницу слушаться системных настроек.

Также мы научились хранить состояние переключателей на устройстве.

Всё это живёт на нашей колхозной странице, на которую мы с каждым новым проектом добавляем всё больше элементов. Однажды она будет похожа на лавку торговца на турецком «Гранд базаре», а пока вот результат:

Посмотреть работу переключателей на странице проекта

Из интересного в этом проекте — симпатичный интерфейсный компонент в Bootstrap 5. В одной из будущих статей разберём, что там вообще интересного подвезли.

Готовый код смотрите в статье на сайте.