Тёмная тема перестала быть просто модным трендом — сегодня это ожидаемая пользователями функция, которая снижает нагрузку на глаза, экономит заряд батареи на мобильных устройствах и просто выглядит стильно. В этом руководстве мы разберём, как правильно реализовать переключение между светлой и тёмной темами на вашем сайте с помощью CSS и JavaScript, сохраняя выбор пользователя и учитывая системные настройки.
Почему тёмная тема — это важно
Исследования показывают, что более 80% пользователей предпочитают использовать тёмные темы в вечернее время, а многие — постоянно. Это не просто эстетическое предпочтение: тёмный интерфейс уменьшает синее излучение экрана, что особенно важно при работе в тёмное время суток. Кроме того, на OLED-экранах чёрные пиксели вообще не потребляют энергию, что продлевает автономность устройства.
Важно: реализуя тёмную тему, вы не просто меняете цвета местами. Нужно пересчитывать контрастность, проверять читаемость текста и адаптировать изображения для разных режимов.
Базовый подход: CSS-переменные
Современный способ реализации тем — использование CSS-переменных (custom properties). Это позволяет централизованно управлять цветовой палитрой и легко переключаться между темами.
Определяем цветовые схемы
Создадим корневые переменные для светлой и тёмной тем:
:root {
/* Светлая тема (по умолчанию) */
--bg-primary: #ffffff;
--bg-secondary: #f5f5f5;
--text-primary: #333333;
--text-secondary: #666666;
--accent-color: #4a90e2;
--border-color: #e0e0e0;
}
[data-theme="dark"] {
/* Тёмная тема */
--bg-primary: #121212;
--bg-secondary: #1e1e1e;
--text-primary: #ffffff;
--text-secondary: #b0b0b0;
--accent-color: #64b5f6;
--border-color: #333333;
}
Применяем переменные в стилях
Теперь используем эти переменные во всех элементах:
body {
background-color: var(--bg-primary);
color: var(--text-primary);
transition: background-color 0.3s, color 0.3s;
}
.card {
background-color: var(--bg-secondary);
border: 1px solid var(--border-color);
}
button {
background-color: var(--accent-color);
color: white;
}
JavaScript для переключения тем
Добавим интерактивности с помощью простого скрипта:
class ThemeSwitcher {
constructor() {
this.themeToggle = document.querySelector('#theme-toggle');
this.currentTheme = localStorage.getItem('theme') || 'light';
this.init();
}
init() {
this.setTheme(this.currentTheme);
if (this.themeToggle) {
this.themeToggle.addEventListener('click', () => {
this.toggleTheme();
});
}
// Проверяем системные настройки
this.checkSystemPreference();
}
setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
// Обновляем текст на кнопке если она есть
if (this.themeToggle) {
this.themeToggle.textContent = theme === 'dark'
? 'Переключить на светлую тему'
: 'Переключить на тёмную тему';
}
}
toggleTheme() {
const newTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
this.currentTheme = newTheme;
this.setTheme(newTheme);
}
checkSystemPreference() {
// Если пользователь не делал выбор, используем системные настройки
if (!localStorage.getItem('theme')) {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
if (prefersDark.matches) {
this.setTheme('dark');
}
// Слушаем изменения системных настроек
prefersDark.addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
this.setTheme(e.matches ? 'dark' : 'light');
}
});
}
}
}
// Инициализируем когда DOM загружен
document.addEventListener('DOMContentLoaded', () => {
new ThemeSwitcher();
});
Используйте localStorage для сохранения выбора пользователя между сессиями. Это улучшает пользовательский опыт — посетитель не должен каждый раз переключать тему.
Продвинутые техники
Плавные переходы
Добавьте плавности переключению:
* {
transition: background-color 0.3s ease,
color 0.3s ease,
border-color 0.3s ease;
}
/* Для элементов, которые не должны анимироваться */
img,
video,
iframe {
transition: none;
}
Адаптация изображений
Для разных тем можно использовать разные изображения:
.logo {
background-image: url('logo-light.png');
}
[data-theme="dark"] .logo {
background-image: url('logo-dark.png');
}
Использование CSS-фильтров
Для простой инверсии цветов изображений:
[data-theme="dark"] img {
filter: brightness(0.8) contrast(1.2);
}
Доступность и UX
- Минимальный контраст текста должен быть 4.5:1 для обычного текста и 3:1 для крупного
- Предоставьте видимый переключатель в доступном месте
- Не используйте только цвет для передачи информации
- Тестируйте тему с реальными пользователями
Частые ошибки
- Игнорирование системных настроек пользователя
- Слишком резкие переходы между темами
- Недостаточный контраст в тёмной теме
- Забывают про сохранение выбора пользователя
- Не адаптируют изображения и иконки
FAQ: Часто задаваемые вопросы
Как определить, какую тему предпочитает пользователь?
Используйте медиа-запрос prefers-color-scheme и сохраняйте выбор пользователя в localStorage. Всегда уважайте явный выбор пользователя над системными настройками.
Нужно ли делать отдельную кнопку переключения?
Да, это лучшая практика. Пользователи ожидают контроль над интерфейсом. Разместите переключатель в навигации или настройках.
Как тестировать тёмную тему?
Тестируйте на разных устройствах, при разном освещении, с разными пользователями. Проверяйте контрастность с помощью инструментов вроде Lighthouse или axe DevTools.
Что делать со сторонними виджетами?
Многие популярные виджеты (чат-боты, формы) поддерживают тёмную тему через настройки. Если нет — используйте CSS-фильтры или свяжитесь с разработчиками.
Как быть с печатной версией?
Используйте медиа-запрос @media print для печатной версии, где обычно предпочтительна светлая тема независимо от выбора пользователя.