eduardweb.
UI / UX & CSSIntermediar#dark-mode#css#accessibility#wcag

Dark mode făcut corect: contrast WCAG AA, culori care nu dor și teste reale

De Răzvan Matei, 3 sept. 2026 · 15 vizualizări · 2 like-uri

Postat 3 sept. 2026
css
:root {
  --surface-base: #121212;
  --surface-card: #1e1e24;
  --surface-overlay: #282832;
  --text-primary: #f1f1f5;   /* Contrast ~14:1 cu base */
  --text-secondary: #a1a1aa; /* Contrast ~5.8:1 cu base */
  --accent: #60a5fa;         /* Albastru desaturat pentru 8.2:1 */
  --border: #27272a;
}

.card {
  background-color: var(--surface-card);
  color: var(--text-primary);
  border: 1px solid var(--border);
}

Majoritatea implementărilor de dark mode pe care le văd în code review sunt doar un background: #000 trântit peste un text #fff. Rezultatul arată groaznic, obosește ochii după cinci minute și pică flagrant cerințele de accesibilitate. Dacă vrei o temă întunecată care chiar ajută utilizatorul, ai nevoie de ceva mai multă nuanță.

De ce negrul absolut este o greșeală

La un proiect de fintech unde aveam în jur de 30k utilizatori activi zilnic, am primit zeci de tichete de suport după lansarea dark mode-ului. Oamenii se plângeau că „literele vibrează” sau că le lăcrimează ochii noaptea. Problema se numește halation effect: contrastul extrem dintre negru pur (#000000) și alb pur (#FFFFFF) creează un contur încețoșat în jurul textului pentru cei cu astigmatism (adică vreo 30-40% din utilizatori).

WCAG 2.1 AA cere un raport de contrast de minim 4.5:1 pentru text normal și 3:1 pentru text mare sau elemente de interfață (butoane, borduri de input). Pe fundal negru pur, albul atinge un raport exagerat de 21:1. Soluția este să folosești griuri închise pentru suprafețe — de exemplu #121212 sau #18181b — și un alb stins pentru text, undeva pe la #E4E4E7 sau #F4F4F5. Astfel păstrezi un contrast sănătos de aproximativ 12:1 sau 14:1, perfect lizibil fără să orbească.

Atenție la culorile de accent

A doua greșeală clasică este refolosirea culorilor de brand din tema light direct pe dark. Un albastru vibrant (#0055FF) funcționează decent pe un fundal alb, dar pe un fundal gri închis devine aproape invizibil, având un contrast de doar 2.8:1 (pică WCAG instant).

Când treci pe dark mode, culorile primare trebuie desaturate și crescute în luminozitate (lightness). În loc de albastru saturat, folosești o nuanță pastelată care „stă deasupra” fundalului fără să vibreze optic.

Cum construiești adâncimea fără umbre

Pe o temă luminoasă folosim box-shadow ca să ridicăm cardurile și modalele în spațiu. Pe o temă întunecată, o umbră neagră pe un fundal aproape negru este complet inutilă.

În loc de umbre, folosești luminozitatea suprafeței: cu cât un element e mai sus în ierarhie (Z-index mai mare), cu atât fundalul lui trebuie să fie mai deschis. Suprafața de bază are #121212, un card are #1E1E1E, iar un dialog modal primește #2A2A2A.

Trade-off-ul sincer aici: designul bazat pe suprafețe consumă mai mult timp în faza de design tokens și te obligă să renunți la ideea că economisești bateria pe ecrane OLED prin negru absolut. Da, pe OLED negrul pur închide pixelii, dar uzabilitatea și confortul vizual bat economia infimă de baterie în 99% din aplicațiile web.

Cum testezi fără să ghicești

Nu te baza pe Lighthouse ca singur indicator. Lighthouse verifică doar contrastul static din DOM-ul inițial, dar ratează stările de :hover, :focus-visible sau elementele dinamice montate ulterior.

Eu folosesc extensia axe DevTools direct în browser pentru un scan rapid, combinat cu Colour Contrast Analyser (CCA) instalat la nivel de OS pentru verificat manual culori din popover-e și grafice SVG. Și cel mai bun test empiric: deschide aplicația pe un laptop cu luminozitatea ecranului la 30%, într-o cameră întunecată, la ora 10 seara. Dacă simți nevoia să mijești ochii sau dacă te dor tâmplele după două minute, culorile tale sunt greșite.

Voi cum gestionați token-urile de culoare între light și dark? Aveți o scală HSL automată sau le mapați manual în Figma și CSS?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.