Back

Как создать переключатель темного режима с помощью CSS и JavaScript

Как создать переключатель темного режима с помощью CSS и JavaScript

Темный режим стал неотъемлемой частью современных веб-сайтов. Пользователи ожидают возможности переключения тем в зависимости от окружения, времени суток или личных предпочтений. Это руководство покажет вам, как создать надежный переключатель темного режима, который учитывает системные настройки, запоминает выбор пользователя и использует современные возможности CSS для оптимальной производительности.

Ключевые моменты

  • Создание переключателя темного режима, который учитывает системные настройки и сохраняет выбор пользователя
  • Использование пользовательских CSS-свойств и свойства color-scheme для эффективной работы с темами
  • Реализация JavaScript, предотвращающего мигание нестилизованного контента при загрузке страницы
  • Применение лучших практик доступности для навигации с клавиатуры и программ чтения с экрана

Настройка HTML-структуры

Начните с семантичного HTML, который включает кнопку переключения и объявляет начальную тему:

<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="color-scheme" content="light dark">
    <title>Dark Mode Toggle Demo</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <button type="button" id="theme-toggle" aria-label="Toggle dark mode">
        <span class="toggle-text">Dark</span>
    </button>
    <!-- Your content here -->
</body>
</html>

Атрибут data-theme на элементе HTML управляет нашей темой. Мета-тег color-scheme сообщает браузеру о необходимости адаптировать нативные элементы интерфейса, такие как полосы прокрутки и элементы форм.

Реализация CSS с использованием современных возможностей

Использование пользовательских CSS-свойств и color-scheme

Определите цветовые токены с помощью пользовательских CSS-свойств, затем используйте CSS-свойство color-scheme для стилизации нативных элементов:

:root {
    color-scheme: light dark;
    
    /* Light theme colors (default) */
    --bg-color: #ffffff;
    --text-color: #213547;
    --accent-color: #0066cc;
}

[data-theme="dark"] {
    --bg-color: #1a1a1a;
    --text-color: #e0e0e0;
    --accent-color: #66b3ff;
}

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

Учет системных настроек с помощью prefers-color-scheme

Добавьте поддержку prefers-color-scheme для автоматического соответствия системным настройкам:

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --bg-color: #1a1a1a;
        --text-color: #e0e0e0;
        --accent-color: #66b3ff;
    }
}

Современная функция light-dark()

Для браузеров, поддерживающих функцию light-dark(), вы можете упростить определение цветов:

:root {
    color-scheme: light dark;
}

body {
    background-color: light-dark(#ffffff, #1a1a1a);
    color: light-dark(#213547, #e0e0e0);
}

Эта функция автоматически выбирает подходящий цвет на основе активной цветовой схемы, уменьшая дублирование кода.

JavaScript для переключения и сохранения настроек

Предотвращение мигания темы при загрузке

Разместите этот скрипт сразу после открывающего тега <body>, чтобы предотвратить мигание нестилизованного контента:

<script>
    // Apply saved theme immediately to prevent flash
    (function() {
        const saved = localStorage.getItem('theme');
        if (saved) {
            document.documentElement.setAttribute('data-theme', saved);
        } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
            document.documentElement.setAttribute('data-theme', 'dark');
        }
    })();
</script>

Полная реализация темного режима

Добавьте этот JavaScript для функциональности переключения:

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

// Get current theme
function getTheme() {
    return html.getAttribute('data-theme') || 
           (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
}

// Set theme and update UI
function setTheme(theme) {
    html.setAttribute('data-theme', theme);
    localStorage.setItem('theme', theme);
    updateToggleText(theme);
}

// Update button text
function updateToggleText(theme) {
    const text = toggle.querySelector('.toggle-text');
    text.textContent = theme === 'dark' ? 'Light' : 'Dark';
    toggle.setAttribute('aria-label', `Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`);
}

// Initialize
updateToggleText(getTheme());

// Handle toggle click
toggle.addEventListener('click', () => {
    const current = getTheme();
    setTheme(current === 'dark' ? 'light' : 'dark');
});

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

Доступность и лучшие практики

Основные функции доступности

Ваш переключатель темного режима должен быть доступен с клавиатуры и правильно размечен:

#theme-toggle:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

Обеспечьте достаточную контрастность цветов в обеих темах. Темный режим не означает низкую контрастность — поддерживайте как минимум стандарты WCAG AA (4.5:1 для обычного текста).

Чего следует избегать

Не используйте filter: invert(1) для всей страницы — это инвертирует изображения и медиафайлы без необходимости. Избегайте чисто черных (#000000) фонов в темном режиме. Используйте темно-серые цвета (#1a1a1a) для лучшей читаемости. Никогда не полагайтесь исключительно на JavaScript без CSS-запасных вариантов.

Тестирование вашей реализации

Протестируйте переключатель темного режима в различных сценариях:

  1. Очистите localStorage и убедитесь, что определение системных настроек работает
  2. Переключите тему и обновите страницу, чтобы подтвердить сохранение настроек
  3. Измените системные настройки при открытом сайте
  4. Проверьте коэффициенты контрастности с помощью инструментов разработчика браузера
  5. Протестируйте навигацию с клавиатуры и объявления программы чтения с экрана

Заключение

Хорошо реализованное решение темного режима учитывает предпочтения пользователя, сохраняет выбор и использует современные возможности CSS. Комбинируя свойство color-scheme, пользовательские свойства и минимальный JavaScript, вы создаете переключатель тем, который производителен, доступен и удобен для пользователя. Функция light-dark() упрощает управление цветами для современных браузеров, в то время как запасные варианты обеспечивают совместимость.

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

Часто задаваемые вопросы

Да, вы можете использовать CSS медиа-запросы с prefers-color-scheme для определения системных настроек. Однако JavaScript необходим для сохранения предпочтений пользователя и предоставления кнопки ручного переключения, которая переопределяет системные настройки.

Это происходит, когда JavaScript выполняется после рендеринга страницы. Разместите скрипт сразу после тега body, который проверяет localStorage и применяет сохраненную тему до отрисовки страницы, чтобы предотвратить это мигание.

Нет, чисто черный цвет может вызвать напряжение глаз и затруднить чтение текста. Вместо этого используйте темно-серые цвета, такие как #1a1a1a или #121212. Эти цвета снижают напряжение, сохраняя при этом хорошие коэффициенты контрастности для доступности.

Избегайте использования filter invert для изображений. Вместо этого предоставьте альтернативные версии изображений для темного режима или используйте прозрачные PNG с цветами, которые работают на обоих фонах. Для сложной графики рассмотрите использование CSS-масок или SVG с currentColor.

Truly understand users experience

See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..

OpenReplay