Иконка смены темы чаще всего перестаёт работать из-за того, что скрипт переключения загружается раньше, чем сама кнопка в DOM, — проверьте в консоли браузера ошибку Cannot read properties of null, это первый признак именно такой проблемы. Если ошибки нет, а тема не меняется, причина обычно в том, что CSS-переменные или класс переключения не привязаны к корневому элементу <html> или <body>.
Эта статья разбирает всё, что связано с иконкой смены темы: какие символы использовать, как реализовать переключатель на чистом HTML, CSS и JavaScript, как сохранять выбор пользователя и какие ошибки встречаются чаще всего. Материал подойдёт и тем, кто делает переключатель с нуля, и тем, кто пытается починить уже существующий.
Какой символ выбрать для иконки смены темы
Универсального стандарта не существует, но пользователи уже привыкли к нескольким устойчивым обозначениям. Самые узнаваемые — солнце для светлой темы и луна (полумесяц) для тёмной. Логика проста: иконка показывает либо текущее состояние, либо тему, на которую произойдёт переключение. Оба подхода встречаются в популярных интерфейсах, поэтому важно выбрать один и придерживаться его последовательно.
Альтернативные варианты:
- 🌞 Солнце и луна в одной иконке, разделённые диагональю — компактно, но менее очевидно;
- 🔆 Кнопка с текстом «Тёмная тема» / «Светлая тема» — максимально понятно, но занимает место;
- 🎨 Палитра — подходит, если тем несколько, а не две;
- 💡 Лампочка — метафора «включить/выключить свет», легко читается.
Готовые иконки можно взять из открытых наборов — например, Material Symbols, Feather Icons или Font Awesome. Используйте формат SVG: он масштабируется без потери качества и позволяет менять цвет через CSS-свойство fill или stroke, что критично при смене темы.
Базовая реализация переключателя на HTML и CSS
Минимальная рабочая схема строится на переключении класса у корневого элемента. Кнопка с иконкой добавляется в шапку сайта, а стили тёмной темы описываются через селектор класса или атрибута.
<button id="theme-toggle" aria-label="Сменить тему">
<svg>...</svg>
<svg>...</svg>
</button>
Обе иконки размещаются внутри одной кнопки, а видимость каждой управляется CSS: в светлой теме показывается луна, в тёмной — солнце. Это надёжнее, чем подменять содержимое кнопки через JavaScript, — переключение происходит мгновенно и без мерцания.
.icon-moon { display: none; }
[data-theme="dark"] .icon-moon { display: inline; }
[data-theme="dark"] .icon-sun { display: none; }
⚠️ Внимание: не привязывайте стили тёмной темы только к классу на кнопке. Класс или атрибутdata-themeдолжен ставиться на<html>или<body>, иначе перекрасится только сама иконка, а страница останется прежней.
JavaScript-логика и сохранение выбора пользователя
Обработчик клика переключает атрибут темы и сохраняет выбор в localStorage, чтобы при следующем визите тема применялась автоматически. Это базовый минимум, без которого переключатель теряет смысл.
const btn = document.getElementById('theme-toggle');
btn.addEventListener('click', () => {
const current = document.documentElement.dataset.theme;
const next = current === 'dark' ? 'light' : 'dark';
document.documentElement.dataset.theme = next;
localStorage.setItem('theme', next);
});
При загрузке страницы нужно прочитать сохранённое значение. Если его нет, разумно ориентироваться на системную настройку пользователя через медиазапрос prefers-color-scheme — так сайт сразу откроется в той теме, которая установлена в операционной системе.
☑️ Проверка переключателя темы
Мерцание при загрузке: как убрать
Частая жалоба: при открытии страницы с сохранённой тёмной темой на долю секунды появляется светлый фон, затем всё перекрашивается. Причина — скрипт восстановления темы выполняется после отрисовки страницы. Решение — вынести чтение localStorage в небольшой синхронный скрипт внутри <head>, до подключения стилей и контента.
Инлайн-скрипт восстановления темы должен стоять в <head> до CSS — это единственный способ полностью убрать вспышку светлой темы при загрузке. Асинхронные и отложенные скрипты для этой задачи не подходят.
Готовый фрагмент для head
(function(){var t=localStorage.getItem('theme');if(!t){t=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light';}document.documentElement.dataset.theme=t;})(); — вставьте этот код первым скриптом в head страницы.
Типичные ошибки и их решения
Ниже собраны проблемы, с которыми чаще всего сталкиваются при добавлении иконки смены темы. Сначала выполняйте безопасные проверки в консоли браузера и инспекторе элементов — этого достаточно для диагностики большинства случаев.
| Симптом | Вероятная причина | Что проверить |
|---|---|---|
| Клик по иконке ничего не делает | Скрипт выполнился до появления кнопки в DOM | Перенести скрипт в конец body или использовать DOMContentLoaded |
| Иконка меняется, фон — нет | Класс ставится на кнопку, а не на html/body | Проверить, где выставляется data-theme |
| Тема сбрасывается при переходе между страницами | Нет сохранения в localStorage или чтение происходит слишком поздно | Проверить вкладку Application в DevTools |
| Иконка не видна на тёмном фоне | Цвет SVG задан жёстко | Использовать fill="currentColor" в SVG |
| Вспышка светлой темы при загрузке | Восстановление темы в отложенном скрипте | Перенести чтение темы в инлайн-скрипт в head |
⚠️ Внимание: если сайт работает на CMS или конструкторе (WordPress, Tilda и подобных), встроенные механизмы кеширования могут отдавать старую версию страницы без ваших изменений. Перед диагностикой «неработающего» переключателя очистите кеш сайта и проверьте страницу в режиме инкогнито.
Доступность и мелочи, которые часто упускают
Иконка без подписи непонятна скринридерам, поэтому атрибут aria-label обязателен. Желательно также обновлять его текст при переключении: «Включить тёмную тему» / «Включить светлую тему». Кроме того, кнопка должна быть доступна с клавиатуры — нативный элемент <button> решает это автоматически, а вот самодельный <div> с обработчиком клика — нет.
Ещё один нюанс — контрастность самой иконки. Проверьте, что она различима на обоих фонах: светлом и тёмном. Проще всего этого добиться, задав иконке currentColor, чтобы она наследовала цвет текста и автоматически адаптировалась к активной теме.
Иконка смены темы в мобильных приложениях и операционных системах
Вне веба переключатель темы встречается в настройках Android, iOS и Windows. Путь к нему зависит от версии системы и оболочки производителя, поэтому универсальной инструкции нет — обычно переключатель находится в разделе настроек экрана или персонализации, а на многих устройствах продублирован в шторке быстрых настроек. Если иконка там отсутствует, сверьтесь с документацией именно вашей модели устройства и версии ОС.
В приложениях иконка смены темы обычно располагается в настройках внешнего вида. Если после обновления приложения переключатель пропал, возможная причина — разработчик заменил ручной выбор на автоматическое следование системной теме. Проверьте, нет ли в настройках пункта вида «Оформление» или «Тема» с вариантом «Как в системе».
Частые вопросы
Какая иконка понятнее: солнце или луна?
Оба варианта привычны пользователям. Чаще иконка показывает тему, на которую произойдёт переключение: в светлой теме отображается луна, в тёмной — солнце. Главное — не смешивать обе логики на одном сайте.
Можно ли сделать переключатель темы без JavaScript?
Частично — через чекбокс и CSS-селектор :checked, но сохранить выбор между страницами без скрипта не получится. Для полноценной реализации JavaScript необходим.
Почему тема сбрасывается после перезагрузки страницы?
Скорее всего, выбор не сохраняется в localStorage или сохранённое значение не читается при загрузке. Проверьте вкладку Application → Local Storage в инструментах разработчика.
Как сделать, чтобы тема совпадала с системной?
Используйте медиазапрос prefers-color-scheme: dark в CSS или одноимённую проверку через matchMedia в JavaScript, когда пользователь ещё не делал ручной выбор.
Иконка SVG не меняет цвет при смене темы — что делать?
Проверьте, не задан ли цвет жёстко в атрибутах fill или stroke внутри SVG. Замените их на currentColor — тогда иконка унаследует цвет текста и будет перекрашиваться вместе с темой.