Колись, роблячи нову тему для свого сайту, я довго бродив по форумах, як сліпе кошеня, у пошуках способу запам'ятати вибір відвідувача: темний дизайн чи світлий. Перепробував купу вбудованих методів WordPress, а закінчилося все маленьким скриптом на JavaScript. Відтоді браузери навчилися багато чого нового, тож розповім, як сьогодні просто і правильно записати, прочитати й видалити cookies на будь-якому сайті, без прив'язки до CMS.

Що таке cookies

Cookie (кука, «реп'яшок») – це маленький шматочок тексту на кшталт theme=dark, який сайт залишає у браузері відвідувача. Головна особливість: браузер сам відправляє всі куки сайту на сервер з кожним запитом. Тож сервер ще до того, як віддасть сторінку, знає, що ти обрав/ла темну тему, мову чи вже закрив/ла набридливе повідомлення.

Розмір у кук невеликий, близько 4 КБ на одну, тому зберігають у них лише короткі значення, а не цілі масиви даних.

Як записати cookie в JavaScript

З JavaScript до кук доступ через document.cookie. Виглядає воно трохи дивно: присвоєння не затирає всі куки, а додає чи оновлює одну:

document.cookie = 'theme=dark; max-age=31536000; path=/; SameSite=Lax; Secure';

Після назви й значення через крапку з комою йдуть параметри:

  • max-age – скільки секунд жити куці. 31536000 – це рік. Якщо параметра немає, кука зникне, щойно відвідувач закриє браузер.
  • path=/ – кука доступна на всіх сторінках сайту, а не лише в поточній теці. Без нього кука, записана на сторінці /blog/post, не буде видна на головній, і ти довго шукатимеш, чому нічого не працює. Я шукав 🙂
  • SameSite=Lax – браузер не надсилатиме куку, коли запит іде з чужого сайту (крім звичайного переходу за посиланням). Це захист від частини атак, і сучасні браузери й так ставлять Lax за замовчуванням, але краще вказати явно.
  • Secure – кука передається лише через HTTPS. На робочому сайті ставлю завжди, а от на локальному сервері без HTTPS її доведеться прибрати, інакше кука не запишеться.

Три зручні функції

Щоразу писати такий рядок незручно, тому я тримаю під рукою три маленькі функції:

function setCookie(name, value, days = 365) {
    document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value)
        + '; max-age=' + days * 86400
        + '; path=/; SameSite=Lax; Secure';
}

function getCookie(name) {
    const prefix = encodeURIComponent(name) + '=';
    const found = document.cookie.split('; ').find(item => item.startsWith(prefix));
    return found ? decodeURIComponent(found.slice(prefix.length)) : null;
}

function deleteCookie(name) {
    document.cookie = encodeURIComponent(name) + '=; max-age=0; path=/';
}

Що тут варто знати:

  • encodeURIComponent() потрібен, щоб у значенні можна було зберегти пробіли, кому чи кирилицю, – без нього крапка з комою в тексті просто «зламає» куку.
  • document.cookie при читанні повертає всі куки одним рядком на кшталт theme=dark; lang=uk, тож ми розбиваємо його і шукаємо потрібну.
  • Видалити куку можна лише одним способом – записати її з max-age=0. І path має бути той самий, що й під час запису, інакше браузер вважатиме це іншою кукою.

Користуватися ними просто:

setCookie('theme', 'dark');      // запам'ятати на рік
getCookie('theme');              // 'dark' або null
deleteCookie('theme');           // забути

Приклад: запам'ятати тему сайту

Повернімося до моєї старої задачі з темним і світлим дизайном. Кнопка в розмітці:

<button class="theme-switch" type="button">Змінити тему</button>

Скрипт перемикає клас dark на тезі <html> і записує вибір у куку:

document.querySelector('.theme-switch').addEventListener('click', () => {
    const isDark = document.documentElement.classList.toggle('dark');
    setCookie('theme', isDark ? 'dark' : 'light');
});

А тепер найцікавіше, заради чого тут варто брати саме куки. Оскільки браузер надсилає їх на сервер, сайт на PHP може одразу віддати сторінку з потрібним класом:

<?php $theme = ($_COOKIE['theme'] ?? '') === 'dark' ? 'dark' : ''; ?>
<html lang="uk" class="<?= $theme ?>">

І ніякого блимання світлою сторінкою перед тим, як спрацює скрипт. Зверни увагу: значення з куки я не вставляю в HTML як є, а лише порівнюю. Відвідувач може записати в куку що завгодно, тож довіряти їй сліпо не можна.

У своїх темах WordPress підключай такий скрипт через wp_enqueue_script() – як це робиться, я показував у статті про файл functions.php. А як працює classList.toggle(), детально розібрано в статті як змінити клас елемента в JavaScript.

Cookies чи localStorage?

Для того ж темного режиму можна взяти і localStorage – про це я писав у статті темний режим на сайті за допомогою localStorage. Як вибрати:

  • Cookies – коли значення потрібне серверу: тема, мова, згода на щось. Але вони їдуть з кожним запитом, тож пхати туди багато даних не варто.
  • localStorage – коли дані потрібні лише скрипту в браузері: налаштування інтерфейсу, чернетка форми, кеш. Місця там набагато більше, і на сервер нічого не відправляється.

Є й новіший спосіб працювати з куками – cookieStore, з нормальними методами get(), set() і delete(). Він асинхронний і значно зручніший, але старі браузери його не знають, тож для простих задач функцій вище цілком досить.

А що зі згодою на cookies?

Ті самі банери «Цей сайт використовує cookies» з'явилися через європейські правила приватності. Якщо коротко: кука, яка просто запам'ятовує вибір теми чи мови, потрібна для роботи сайту, і окремої згоди на неї зазвичай не просять. А от для аналітики, реклами й усіляких віджетів соцмереж згоду треба отримати до того, як вони запишуть свої куки. У будь-якому разі чесно опиши в політиці конфіденційності, які куки використовує твій сайт і навіщо.

І ще одна порада з безпеки: ніколи не зберігай у куках з JavaScript паролі чи токени входу. Куки для авторизації сервер ставить сам із прапорцем HttpOnly, і тоді скрипти на сторінці їх просто не бачать.

Що далі

Якщо в тебе тема на WordPress і хочеться перемикати цілі файли стилів, глянь кнопку перемикання стилю шаблона WordPress. Більше про це – за позначками JavaScript та Front-end розробка.

А ти зберігаєш налаштування відвідувачів у куках чи вже повністю перейшов/ла на localStorage? Пиши в коментарях 🙂