Решён
Как сделать функцию переключения темы сайта?

TS Lover JavaScript
3k
5

Делаю лендинг, хочу добавить переключатель светлая/темная тема. Сам сайт на чистом HTML/CSS/JS, без фреймворков.

Понимаю что нужно менять CSS переменные, но не понимаю как:

  1. Сохранить выбор пользователя чтобы при перезагрузке не сбрасывалось
  2. Учитывать системные настройки (если у пользователя в системе темная тема)

Может есть готовое решение скопировать?

Решение
48
Участник • 3 ответа

Полное решение:

CSS:

:root {
  --bg: #ffffff;
  --text: #1a1a1a;
}

[data-theme="dark"] {
  --bg: #1a1a1a;
  --text: #f5f5f5;
}

body {
  background: var(--bg);
  color: var(--text);
  transition: background 0.3s, color 0.3s;
}

JS:

const toggle = document.getElementById('theme-toggle');

// Проверяем сохраненную тему или системные настройки
const getPreferredTheme = () => {
  const saved = localStorage.getItem('theme');
  if (saved) return saved;
  return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
};

// Применяем тему
const setTheme = (theme) => {
  document.documentElement.setAttribute('data-theme', theme);
  localStorage.setItem('theme', theme);
};

// Инициализация
setTheme(getPreferredTheme());

// Переключение
toggle.addEventListener('click', () => {
  const current = document.documentElement.getAttribute('data-theme');
  setTheme(current === 'dark' ? 'light' : 'dark');
});

Атрибут data-theme вешается на html, localStorage сохраняет выбор между сессиями, matchMedia проверяет системные настройки при первом визите.

Аватар TS Lover

Работает идеально, спасибо. Единственное - добавил проверку на null в getPreferredTheme чтобы линтер не ругался

24
Участник • 2 ответа

Добавь слушатель на изменение системной темы, чтобы сайт реагировал если пользователь переключит в системе:

window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', e => {
    if (!localStorage.getItem('theme')) {
      setTheme(e.matches ? 'dark' : 'light');
    }
  });

Только если пользователь сам не выбирал тему на сайте.

38
Участник • 1 ответ

Важный нюанс: скрипт переключения темы нужно подключать в head с атрибутом blocking или инлайном ДО загрузки body. Иначе будет FOUC - flash of unstyled content. Страница сначала мигнет светлой темой, потом переключится на темную.

<head>
  <script>
    // Инлайн скрипт установки темы
    const theme = localStorage.getItem('theme') || 
      (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
    document.documentElement.setAttribute('data-theme', theme);
  </script>
</head>
7
Эксперт • 1 ответ

Посмотри как сделано на web.dev или на MDN. Там исходники открыты, можно подсмотреть реализацию.

3
Эксперт • 2 ответа

зачем велосипед изобретать, есть же библиотека darkmode.js, подключил одной строкой и все работает из коробки

Написать ответ

Премодерация гостей

Вы отвечаете как гость. Ваш ответ будет скрыт до проверки модератором. Чтобы ответ появился сразу и вы получали репутацию — войдите в аккаунт.

Будьте вежливы и соблюдайте правила платформы.