IT forum Ukraine

Повна версія: Dark Mode без JavaScript: використовуємо магію селектора :has()
Зараз ви переглядаєте скорочену версію нашого вмісту. Переглянути повну версію з відповідним форматуванням.
Привіт, ком'юніті! Раніше для реалізації перемикача темної теми (Dark Mode) нам обов'язково потрібен був JavaScript, щоб вішати клас на `<body>`. Але часи змінюються!

Зараз, завдяки потужному селектору **:has()**, ми можемо керувати станом всієї сторінки прямо з CSS, спираючись на стан одного чекбокса.

### Як це працює?
Ми оголошуємо змінні в `:root`, а потім змінюємо їхні значення, якщо в тілі документа є активований чекбокс.

Код:
:root {
  --bg-color: #ffffff;
  --text-color: #1a1a1a;
}

/* Магія починається тут */
body:has(#theme-toggle:checked) {
  --bg-color: #1a1a1a;
  --text-color: #f0f0f0;
}

body {
  background-color: var(--bg-color);
  color: var(--text-color);
  transition: 0.3s ease;
}

### Переваги:
1. **Нуль рядків JS** для перемикання теми.
2. Немає 'блимання' білим фоном при завантаженні, якщо правильно налаштувати інлайновий CSS.
3. Код стає набагато чистішим.

Ви вже використовуєте `:has()` у своїх проектах? Які ще круті кейси знайшли для цього селектора?
Це виглядає дуже круто! `:has()` — це справді 'батьківський селектор', про який ми мріяли років 15. Але як щодо підтримки браузерів? Останнім часом вона значно покращилась, але чи готові ми до продакшну без фолбеків?
Підтримка зараз вже більше 92% (всі сучасні Chrome, Firefox, Safari його розуміють). Я б порадила комбінувати цей метод з медіа-запитом `prefers-color-scheme`.

Код:
@media (prefers-color-scheme: dark) {
  :root {
    --bg-color: #1a1a1a;
    --text-color: #f0f0f0;
  }
}
Тоді юзер отримає темну тему автоматично за системним налаштуванням, а через чекбокс зможе її змінити вручну.
Є один нюанс: CSS не вміє зберігати стан після перезавантаження сторінки. Тобто якщо юзер перемкнув чекбокс і оновив вкладку — тема злетить до дефолтної. Тому один рядок JS для запису в `localStorage` все ж таки знадобиться, якщо ми хочемо гарний UX.
@Olena_Top, згоден, для справжньої персистентності JS поки що незамінний. Проте, цей метод ідеальний для невеликих лендінгів або прототипів, де ми хочемо мінімізувати сторонні скрипти. А щодо `:has()`, він також чудово підходить для валідації форм — наприклад, підсвічувати батьківський блок `.form-group`, якщо внутрішній інпут невалідний!