:root {
/* Light Mode Tokens */
--bg-primary: #ffffff;
--bg-surface: #f4f4f5;
--text-main: #18181b;
--color-primary: #2563eb; /* Albastru saturat */
--color-error: #dc2626;
}
[data-theme="dark"] {
/* Dark Mode Accessible Tokens (WCAG AA Compliant) */
--bg-primary: #121214; /* Gri închis, NU #000000 */
--bg-surface: #1c1c20; /* Suprafață mai elevată = mai deschisă */
--text-main: #f4f4f5; /* Off-white, NU #ffffff */
--color-primary: #60a5fa; /* Variantă desaturată & mai luminoasă */
--color-error: #f87171; /* Vizibil și lizibil la 4.5:1+ */
}
body {
background-color: var(--bg-primary);
color: var(--text-main);
transition: background-color 0.2s ease, color 0.2s ease;
}Mulți dev își închipuie că dark mode înseamnă să schimbi background: #fff cu #000 și color: #000 cu #fff. Am făcut și eu greșeala asta acum vreo 4 ani pe un dashboard financiar cu peste 14k utilizatori activi zilnic. În mai puțin de 48 de ore am primit zeci de tichete în Support că textul obosește ochii și că hărțile de date erau imposibil de citit.
Accessibility-ul pe dark mode nu e doar o chestie de „design drăguț”, ci de lizibilitate reală. Hai să vedem unde se greșește cel mai des și cum o rezolvi fără să devii expert în teoria culorilor.
Negrul pur (#000000) e inamicul ochilor
Negrul absolut combinat cu alb pur (#FFFFFF) creează un efect optic numit halation (un fel de halou sau sângerare a textului). Pe monitoarele OLED sau cele cu luminozitate mare, lumina albă proiectată din negrul stins taie agresiv retina.
În practică, fundalul principal ar trebui să fie un gri foarte închis, cum ar fi #121212, #161618 sau #1e1e24. Pentru nivele superioare (carduri, modale, dropdown-uri), în loc să folosești umbre pe care oricum nu le vede nimeni pe fundal închis, crești treptat luminozitatea griului (#24242a, #2c2c32).
Regula WCAG AA și culorile de brand
Standardul WCAG 2.1 AA cere un raport minim de contrast de 4.5:1 pentru text normal și 3:1 pentru text mare sau elemente de interfață (butoane, inputuri).
Cea mai mare capcană e să iei albastrul sau roșul tău primar din light mode și să-l trântești netransformat pe dark mode. Culorile saturate pe fundal închis creează vibrație cromatică și distrug contrastul.
Soluția e simplă: desaturezi culorile accentuate cu 20-30% și le crești puțin luminozitatea. Un roșu de eroare #D32F2F din light mode devine un pastel cald #F87171 pe întuneric. Are contrast mai bun și nu arată ca un bec de avarie.
CSS Variables și dilema toggle vs sistem
O abordare curată presupune să lucrezi cu jetoane de culoare (color tokens) mapate pe CSS variables. În proiectele recente folosesc @media (prefers-color-scheme: dark) ca bază, dublat de o clasă sau atribut pe <html> pentru override manual.
Exista tentația de a folosi noua funcție CSS light-dark(). E excelentă pentru prototipare rapidă, dar are un trade-off sincer: dacă vrei să dai posibilitatea utilizatorului să-și salveze preferința într-un cookie/localStorage indiferent de setarea din OS, tot la atribute gen data-theme="dark" ajungi pentru că poți suprascrie mai ușor cascadarea.
Cum testezi totul în 30 de secunde
Nu ai nevoie de unelte scumpe ca să verifici dacă ești în parametri:
- Chrome / Firefox DevTools: Dai Inspect pe orice text. În caseta de culoare vei vedea indicatorul Contrast ratio. Dacă are bifa verde pe AA, ești ok.
- Rendering Tab: În Chrome DevTools apăs
Ctrl+Shift+P(sauCmd+Shift+P), caut Rendering și folosesc Emulate CSS media feature prefers-color-scheme. Comuți instant între meciuri. - Simulare de deficiențe de vedere: Tot din Rendering poți simula daltonismul (deuteranopia, protanopia). Un buton verde pe fundal închis s-ar putea să dispară complet pentru unii useri.
Voi cum abordați tăierea temelor în proiecte mari? Mergeți pe auto-detect din OS sau lăsați mereu un toggle la vedere?