Темна тема
Клас на html, блокуючий скрипт проти спалаху і чому inline в @theme обов'язковий.
Тема перемикається класом .dark на <html>, а не медіазапитом. Медіазапит
не дав би користувачеві вибору — а вибір потрібен: ту саму систему вмикають
і вдень біля вікна, і вночі.
Чому компоненти не мають dark:-префіксів
Утиліти посилаються на CSS-змінні, а .dark перевизначає самі змінні. Тому
bg-card працює в обох темах без жодного dark:bg-....
Це тримається на одному слові в theme.css:
@theme inline {
--color-card: var(--bg-card);
}
Без inline Tailwind підставив би значення змінної в момент генерації,
і bg-card назавжди застигла б білою. Це найлегша помилка в усій системі й
найважча для діагностики: усе виглядає правильно, поки не перемкнеш тему.
Спалах при завантаженні
Сторінки прередерені, і в їхньому HTML класу .dark немає — його ставить
лише клієнт. Без запобіжника користувач із темною темою бачив би білий
спалах на кожному завантаженні, поки не відпрацює гідрація.
Тому в <head> стоїть блокуючий скрипт, який виконується до першого
малювання:
(() => {
try {
const s = localStorage.getItem('tatetui-theme')
const d = s ? s === 'dark' : matchMedia('(prefers-color-scheme:dark)').matches
if (d) document.documentElement.classList.add('dark')
} catch (e) {}
})()
try/catch обов'язковий: у приватному режимі Safari звернення до
localStorage кидає виняток, і без нього сторінка не намалювалася б узагалі.
Джерело правди — DOM, а не сховище
useTheme() читає початкове значення з класу на <html>, а не з
localStorage. Клас уже поставив скрипт вище, і саме він — джерело правди.
Якби composable читав сховище сам, сервер і клієнт розійшлися б у першому рендері прередереної сторінки, і Vue лаявся б на невідповідність гідрації.
Що перевіряти в кожному компоненті
Тіні. У світлій темі --shadow-card це 4% чорного — на темному тлі такого
просто не видно, і картка «злипається» з фоном. Тому в темній темі тіні
сильніші, і це задано токеном, а не класом.
Напівпрозорі підкладки. bg-primary-900/30 над майже чорним тлом дає
видимий результат лише тому, що --brand-900 у темній темі світліший.
Якщо додаєте власний відтінок — перевірте його саме в такому вживанні.