N1Nex1on
N1Nex1on

Фішки оформлення

Темна тема без блимання: перемикач, який запам'ятовує вибір

25.10.2026 · NexVoid

4 мин чтения

Кнопка темної теми, що не спалахує білим під час перезавантаження: короткий скрипт у head, light-dark() і color-scheme. Код цілком, знімки на телефоні, планшеті й комп'ютері та перевірка, що спалаху немає.

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

Що вийде #

  • Тема за замовчуванням збігається з темою системи (світлою чи темною) і працює навіть за вимкненого JavaScript.
  • Кнопка перемикає тему, а вибір запам'ятовується в браузері.
  • Збережений вибір застосовується до першого малювання: під час перезавантаження немає білого спалаху.
Темна тема на телефоні, ширина 390: шапка з кнопкою «Темна» і картка
Темна тема на телефоні, ширина 390: шапка з кнопкою «Темна» і картка
Темна тема на планшеті, ширина 768
Темна тема на планшеті, ширина 768
Темна тема на комп'ютері, ширина 1280: картка посередині, зайвого немає
Темна тема на комп'ютері, ширина 1280: картка посередині, зайвого немає

Чому сторінка блимає #

Браузер малює сторінку в міру читання HTML. Якщо вибір користувача застосовує скрипт у кінці сторінки або після завантаження, браузер встигає намалювати світлий варіант, а потім перефарбовує його. Потрібно, щоб вибір був відомий раніше, ніж з'явиться перший піксель, тобто скрипт має стояти на самому початку сторінки, у head.

Крок 1. Оголосіть, що сайт уміє обидві теми #

Покладіть у head рядок meta і одразу за ним крихітний скрипт. Він читає збережений вибір і, якщо він є, записує його в атрибут data-theme кореневого елемента:
headHTML
<meta name="color-scheme" content="light dark">
<script>
(function () {
  var saved = null;
  try { saved = localStorage.getItem('theme'); } catch (e) {}
  if (saved === 'light' || saved === 'dark') {
    document.documentElement.dataset.theme = saved;
  }
})();
</script>
Скрипт короткий і не чекає завантаження сторінки. Блок try потрібен тому, що в приватному режимі або за забороненого сховища браузер кидає помилку, і без нього вся сторінка лишилася б без теми.

Крок 2. Опишіть кольори один раз #

Кольори кожної теми задаються парою значень у функції light-dark(): перше для світлої теми, друге для темної. Потрібне обирає властивість color-scheme:
style.cssCSS
:root {
  color-scheme: light dark;
  --bg: light-dark(#ffffff, #14161a);
  --text: light-dark(#1b1f24, #e6e8eb);
  --card: light-dark(#f3f5f8, #1e2228);
  --line: light-dark(#d8dee6, #2c333c);
  --accent: light-dark(#1a56db, #7aa7ff);
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }
body { background: var(--bg); color: var(--text); }
Поки data-theme немає, працює color-scheme: light dark: сторінка бере тему системи без жодного рядка JavaScript. Коли скрипт записав вибір користувача, два останні рядки примусово вмикають потрібну тему.

Крок 3. Додайте кнопку #

bodyHTML
<button id="theme-toggle" type="button" aria-pressed="false"></button>
Кнопка з двох станів простіша за три («світла, темна, як у системі»): зрозуміло, що натиснуто, і не треба пояснювати третій варіант. Поки людина не натиснула, сайт і так іде за системою.
theme.jsJavaScript
(function () {
  var root = document.documentElement;
  var button = document.getElementById('theme-toggle');
  var names = { dark: 'Темна', light: 'Світла' };

  function current() {
    return root.dataset.theme ||
      (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
  }
  function show() {
    var now = current();
    button.textContent = names[now];
    button.setAttribute('aria-pressed', now === 'dark');
  }

  button.addEventListener('click', function () {
    var next = current() === 'dark' ? 'light' : 'dark';
    root.dataset.theme = next;
    try { localStorage.setItem('theme', next); } catch (e) {}
    show();
  });
  show();
})();
Цей скрипт можна підключити в кінці сторінки: йому не треба встигати до малювання, він лише підписує кнопку й зберігає вибір.

Перевірте самі #

Ми перевірили рецепт у браузері на сторінці, де перед кінцем стоїть повільний скрипт (дві секунди), а в сховищі записано вибір «темна» за світлої теми системи. Через 0,8 секунди після початку завантаження: зі скриптом у head сторінка вже темна, зі скриптом у кінці — біла, і так лишається, доки сторінку не дочитано. Ось що бачить людина в цей момент:
Скрипт у кінці сторінки: вибір «темна» збережено, а сторінка світла, це спалах
Скрипт у кінці сторінки: вибір «темна» збережено, а сторінка світла, це спалах
Скрипт у head: той самий момент завантаження, сторінка одразу темна
Скрипт у head: той самий момент завантаження, сторінка одразу темна

Решту теж перевірено: без JavaScript сторінка бере тему системи, після натискання кнопки й перезавантаження вибір лишається, на 390, 768 і 1280 точок немає бічного скролу.
Повторити можна так:

  1. Відкрийте сторінку, натисніть кнопку й оберіть темну тему.
  2. Увімкніть в інструментах розробника уповільнення мережі й перезавантажте сторінку: тло лишається темним із першого кадру.
  3. Вимкніть JavaScript і очистьте сховище: сторінка знову йде за темою системи.

Типові помилки #

  • Скрипт у кінці сторінки. Спалах повертається: вибір відомий надто пізно.
  • Немає color-scheme на :root. Функція light-dark() без нього не знає, яке значення взяти.
  • Немає try навколо localStorage. У приватному режимі в частини браузерів сторінка ламається.
  • Тема лише в JavaScript. Без скрипта відвідувач лишається без темної теми, навіть коли в системі вона ввімкнена. У рецепті це вирішено через color-scheme.
  • Не перевірено контраст. Текст і тло мають давати не менше 4,5 до 1, це правило доступності WCAG AA. Перевірте обидві теми, а не одну.

← К ленте новостей

Поделиться: Telegram WhatsApp

Читайте также

Обсуждение

Комментарии

Обсуждение ещё не началось

Пока никто не высказался. Будьте первым.

Пожаловаться на запись