Иконка смены темы: выбор, настройка и реализация переключателя

Иконка смены темы чаще всего перестаёт работать из-за того, что скрипт переключения загружается раньше, чем сама кнопка в 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 — так сайт сразу откроется в той теме, которая установлена в операционной системе.

☑️ Проверка переключателя темы

Выполнено: 0 / 5
📊 Какой вариант иконки смены темы вы считаете самым понятным?
Солнце и луна
Лампочка
Палитра
Текстовая кнопка

Мерцание при загрузке: как убрать

Частая жалоба: при открытии страницы с сохранённой тёмной темой на долю секунды появляется светлый фон, затем всё перекрашивается. Причина — скрипт восстановления темы выполняется после отрисовки страницы. Решение — вынести чтение 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 — тогда иконка унаследует цвет текста и будет перекрашиваться вместе с темой.