Колись мені знадобилася на сайті на WordPress кнопка для перемикання між світлим і темним режимами. Я зробив її за вечір: два окремі файли стилів, кука з вибором і перезавантаження сторінки після кожного кліку. Працювало, але блимало і смикалося. Відтоді я переробляв цю кнопку не раз, тож розповім, як зробити темний режим у своїй темі WordPress сьогодні: один файл стилів, автоматичне перемикання разом із системною темою, кнопка без перезавантаження і без білого спалаху при переході між сторінками.
Як це працюватиме
- Кольори задані CSS-змінними, і сайт сам підлаштовується під світлу чи темну тему системи.
- Кнопка дає вибрати тему вручну: скрипт ставить атрибут
data-themeна тег<html>і записує вибір у куку. - На наступній сторінці PHP читає цю куку і одразу віддає
<html data-theme="dark">, тож сторінка з'являється в потрібній темі без жодного блимання.
Загальні принципи темної теми, без прив'язки до WordPress, я детально розібрав у статті темна тема на сайті: CSS, localStorage і системна тема. Тут зосередимося на тому, як вбудувати це в тему WordPress.
Кольори: один файл стилів
Замість двох файлів light.css і dark.css, як у мене колись, достатньо кількох рядків в основному style.css:
:root {
color-scheme: light dark;
--text: light-dark(#282c34, #d4d4d4);
--bg: light-dark(#ffffff, #1e2127);
--accent: light-dark(#34687d, #7fb8cf);
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }
body {
color: var(--text);
background: var(--bg);
}
a {
color: var(--accent);
}
light-dark() повертає перший колір для світлої теми і другий для темної, а яка тема зараз, вирішує color-scheme: без атрибута – як у системі, з атрибутом – як вибрала людина. Далі всюди в стилях пишеш var(--text) замість конкретного кольору, і темна тема з'являється сама.
PHP: тема з куки одразу в розмітці
Найцікавіша частина, заради якої тут варто брати куки, а не localStorage. Браузер надсилає куки на сервер з кожним запитом, тож тема знає вибір відвідувача ще до того, як віддасть сторінку. Додаємо у functions.php:
function mytheme_color_theme() {
$theme = $_COOKIE['theme'] ?? '';
return in_array( $theme, array( 'light', 'dark' ), true ) ? $theme : '';
}
function mytheme_color_theme_attribute( $output ) {
$theme = mytheme_color_theme();
if ( $theme ) {
$output .= ' data-theme="' . esc_attr( $theme ) . '"';
}
return $output;
}
add_filter( 'language_attributes', 'mytheme_color_theme_attribute' );
Що тут відбувається:
mytheme_color_theme()читає куку і повертає її значення, лише якщо цеlightабоdark. Записати в куку відвідувач може що завгодно, тож довіряти їй сліпо не можна.- Фільтр
language_attributesдописує атрибут до тегу<html>. Він спрацьовує, бо в header.php тег виглядає як<html <?php language_attributes(); ?>>. Самheader.phpправити не треба.
Кнопка
У header.php, там, де має бути кнопка:
<button class="theme-toggle" type="button"
aria-label="<?php esc_attr_e( 'Dark theme', 'mytheme' ); ?>"
aria-pressed="<?php echo 'dark' === mytheme_color_theme() ? 'true' : 'false'; ?>">
<span class="theme-toggle-knob" aria-hidden="true"></span>
</button>
Колись у мене це було посилання з onclick. Але дія на сторінці – це кнопка <button>: на неї можна перейти клавіатурою, і програми для незрячих розуміють, що це. Атрибут aria-pressed каже їм, увімкнена темна тема чи ні, а aria-label дає кнопці назву, бо тексту в ній немає.
Скрипт: перемикання без перезавантаження
Створюємо файл assets/js/theme-toggle.js:
const toggle = document.querySelector('.theme-toggle');
const root = document.documentElement;
const systemDark = matchMedia('(prefers-color-scheme: dark)');
function currentTheme() {
return root.dataset.theme || (systemDark.matches ? 'dark' : 'light');
}
function updateButton() {
toggle.setAttribute('aria-pressed', currentTheme() === 'dark');
}
if (toggle) {
toggle.addEventListener('click', () => {
const next = currentTheme() === 'dark' ? 'light' : 'dark';
root.dataset.theme = next;
document.cookie = 'theme=' + next + '; max-age=31536000; path=/; SameSite=Lax; Secure';
updateButton();
});
systemDark.addEventListener('change', updateButton);
updateButton();
}
Клік ставить атрибут data-theme – і кольори на сторінці змінюються миттєво, без перезавантаження. Заодно вибір записується в куку на рік, щоб наступну сторінку PHP одразу віддав у тій самій темі. Якщо людина нічого не вибирала, а темна тема в неї системна, updateButton() при завантаженні сам виправить стан кнопки. Детальніше про параметри куки (path, SameSite, Secure) читай у статті cookies у JavaScript: як записати і прочитати.
Підключаємо скрипт у functions.php:
function mytheme_theme_toggle_script() {
wp_enqueue_script(
'mytheme-theme-toggle',
get_template_directory_uri() . '/assets/js/theme-toggle.js',
array(),
null,
true
);
}
add_action( 'wp_enqueue_scripts', 'mytheme_theme_toggle_script' );
Оформлення кнопки
Колись для сонця й місяця я брав Font Awesome і два окремі набори стилів для кнопки. Але простий перемикач-повзунок малюється взагалі без іконок:
.theme-toggle {
position: relative;
width: 3.5em;
height: 2em;
padding: 0;
border: 2px solid currentColor;
border-radius: 1em;
background: none;
color: inherit;
cursor: pointer;
}
.theme-toggle-knob {
position: absolute;
top: 0.15em;
left: 0.15em;
width: 1.45em;
height: 1.45em;
border-radius: 50%;
background: currentColor;
transition: transform 0.3s;
}
.theme-toggle[aria-pressed="true"] .theme-toggle-knob {
transform: translateX(1.45em);
}
Зверни увагу на останнє правило: вигляд кнопки залежить від того самого aria-pressed, який читають програми для незрячих. Тож вигляд і стан кнопки ніколи не розійдуться. А currentColor бере колір тексту, тож у темній темі повзунок сам стане світлим.
Увага: плаґіни кешування
У цього способу є одна пастка. Плаґіни кешування зберігають готовий HTML сторінки і віддають його всім однаковим. Якщо першим сторінку відкрив хтось із темною темою, у кеш потрапить <html data-theme="dark"> – і її побачать усі.
Є два виходи. Деякі плаґіни кешування вміють зберігати окремі копії сторінки залежно від куки – пошукай у налаштуваннях щось на кшталт виключень або варіацій за cookie. А якщо такого немає, прибери PHP-частину і відновлюй тему маленьким скриптом у <head> з localStorage – як це зробити, я показував у статті про темну тему на сайті.
А якщо стилі зовсім різні?
Буває, що темна версія відрізняється не лише кольорами, а цілим набором стилів. Тоді можна, як колись я, підключати окремий файл через wp_enqueue_style(), коли mytheme_color_theme() повертає dark. Але без перезавантаження таке перемикання вже не зробиш, а системну тему доведеться обробляти окремо, тому я завжди спершу пробую обійтися змінними.
Що далі
Поруч із перемикачем теми на телефоні зазвичай живе меню – ось як зробити кнопку-бургер на CSS. А якщо ти робиш тему з нуля, почни зі статті як створити тему WordPress з нуля.
Більше про це – за позначками Створення тем WordPress та CSS.
А на твоєму сайті темна тема вмикається сама чи тільки кнопкою? Пиши в коментарях 🙂


Прокоментувати
На сайті відображається лише твоє ім'я та коментар. Електронна пошта зберігається виключно для зв'язку з тобою за потреби та в жодному разі не передається стороннім особам.