Mar 08, 2026
OKLCH in CSS: perché abbandonare RGB e HSL
Guida pratica a OKLCH in CSS: come creare palette bilanciate, sostituire HSL e RGB e migliorare il tuo design system con esempi di codice.
Il problema che probabilmente non sai di avere
Hai mai costruito una palette di colori in HSL, scelto valori di lightness identici per ogni tonalità, e poi notato che il giallo sembrava molto più chiaro del blu — anche se tecnicamente erano “uguali”?
Non è un bug del browser. È un limite strutturale di come HSL e RGB rappresentano il colore.
HSL è stato un grande passo avanti rispetto a RGB: finalmente potevamo ragionare in termini di tonalità, saturazione e luminosità invece di mischiare canali rossi, verdi e blu. Ma HSL ha un difetto fondamentale — la sua L non corrisponde a come il nostro occhio percepisce la luminosità. Due colori con L: 50% possono sembrare completamente diversi in termini di brillantezza percepita.
Ecco perchè esiste OKLCH: uno spazio colore progettato attorno alla percezione umana, non attorno alla fisica dei monitor.
Cosa sono RGB, HSL e OKLCH: un confronto rapido
Prima di entrare nei dettagli di OKLCH, vale la pena capire dove si posiziona rispetto agli spazi colore che già conosci.
RGB
RGB descrive un colore come combinazione di rosso, verde e blu — i tre canali dei pixel dei monitor. È il linguaggio nativo degli schermi, ma è del tutto anti-intuitivo per chi progetta:
color: rgb(41, 182, 246); /* Che colore è? Impossibile dirlo ad'occhio */
Non c’è modo di ricavare visivamente tonalità o luminosità da questi tre numeri. RGB è ottimo per le macchine, pessimo per gli esseri umani.
HSL
HSL nasce proprio per risolvere questo: esprime il colore come Hue (tonalità, 0–360°), Saturation (saturazione, 0–100%) e Lightness (luminosità, 0–100%).
color: hsl(199, 89%, 56%); /* Molto meglio: azzurro chiaro */
È molto più leggibile, ma ha il problema della luminosità non uniforme. Guarda questo esempio:
/* Stesso valore L: 60% — ma percettivamente NON uguali */
.giallo { color: hsl(60, 90%, 60%); }
.blu { color: hsl(220, 90%, 60%); }
.verde { color: hsl(120, 90%, 60%); }
Il giallo sembrerà molto più luminoso del blu. La L di HSL è una bugia (ben intenzionata).
OKLCH
OKLCH usa anch’esso tre assi, ma costruiti su modelli percettivi della visione umana:
- L — Lightness percettiva reale (0–1)
- C — Chroma, ovvero “quanto è saturo” (0–0.4 circa)
- H — Hue, la tonalità in gradi (0–360°)
color: oklch(0.72 0.18 199); /* Azzurro chiaro, lightness davvero uniforme */
La differenza fondamentale: se due colori OKLCH hanno lo stesso valore L, appaiono davvero alla stessa luminosità percepita. Questo cambia tutto quando si tratta di costruire palette.
| Caratteristica | RGB | HSL | OKLCH |
|---|---|---|---|
| Leggibilità umana | ❌ | ✅ | ✅ |
| Lightness percettivamente uniforme | ❌ | ❌ | ✅ |
| Accesso all’intera gamma P3 | ❌ | ❌ | ✅ |
| Adatto per design system | ❌ | ⚠️ | ✅ |
La struttura di oklch() in dettaglio
color: oklch(L C H);
/* oppure con alpha */
color: oklch(L C H / alpha);
Lightness (L)
Va da 0 (nero) a 1 (bianco). A differenza di HSL, questo valore è percettivamente lineare: 0.5 è davvero a metà strada tra il nero e il bianco per il nostro occhio.
oklch(0.2 0.15 250) /* Blu molto scuro */
oklch(0.5 0.15 250) /* Blu medio */
oklch(0.8 0.15 250) /* Blu chiaro */
Chroma (C)
Rappresenta l’intensità o saturazione del colore. 0 è un grigio neutro, valori più alti producono colori più vividi. Il massimo dipende dalla tonalità e dallo spazio colore del dispositivo — su display P3 si può arrivare a circa 0.37.
oklch(0.6 0.0 250) /* Grigio neutro */
oklch(0.6 0.1 250) /* Blu desaturato */
oklch(0.6 0.25 250) /* Blu vivido */
Hue (H)
La tonalità in gradi, come in HSL. Ma attenzione: la disposizione non è identica. In OKLCH, approssimativamente:
0°–30°→ rossi/rosa60°–120°→ gialli/verdi180°–250°→ ciano/blu300°–360°→ viola/magenta
oklch(0.65 0.2 30) /* Arancione */
oklch(0.65 0.2 145) /* Verde */
oklch(0.65 0.2 250) /* Blu */
oklch(0.65 0.2 320) /* Rosa/magenta */
Il vantaggio principale: costruire palette coerenti
Questo è il motivo per cui OKLCH sta conquistando il mondo del CSS moderno. Costruire una palette armonica è banale.
Palette monocromatica
Tieni fissi C e H, varia solo L:
:root {
--brand-900: oklch(0.20 0.18 250);
--brand-700: oklch(0.35 0.18 250);
--brand-500: oklch(0.50 0.18 250);
--brand-300: oklch(0.70 0.18 250);
--brand-100: oklch(0.90 0.18 250);
}
Risultato: cinque varianti dello stesso blu, percettivamente bilanciate. In HSL avresti dovuto aggiustare manualmente ogni valore perché la luminosità reale non è uniforme.
Palette complementare
Stesso L e C, ruota H di 180°:
:root {
--primary: oklch(0.55 0.22 250); /* Blu */
--complementary: oklch(0.55 0.22 70); /* Arancione/giallo */
}
Entrambi i colori avranno la stessa luminosità percepita e la stessa intensità visiva — qualcosa di molto difficile da ottenere con HSL.
Palette analogica
Sposta H di piccoli incrementi:
:root {
--color-1: oklch(0.60 0.20 220); /* Ciano */
--color-2: oklch(0.60 0.20 250); /* Blu */
--color-3: oklch(0.60 0.20 280); /* Indaco */
}
Palette in CSS con custom properties: esempio completo
:root {
/* Colore primario */
--hue-primary: 250;
--chroma-primary: 0.20;
--primary-100: oklch(0.95 calc(var(--chroma-primary) * 0.3) var(--hue-primary));
--primary-300: oklch(0.80 calc(var(--chroma-primary) * 0.6) var(--hue-primary));
--primary-500: oklch(0.60 var(--chroma-primary) var(--hue-primary));
--primary-700: oklch(0.40 var(--chroma-primary) var(--hue-primary));
--primary-900: oklch(0.25 calc(var(--chroma-primary) * 0.8) var(--hue-primary));
/* Basta cambiare --hue-primary per ottenere un nuovo tema */
}
Cambiando un solo valore — --hue-primary — l’intera palette si rigenera in modo percettivamente bilanciato. Prova a fare lo stesso con HSL.
OKLCH per l’accessibilità e il contrasto
La lightness percettivamente uniforme di OKLCH ha un impatto diretto sull’accessibilità. Quando costruisci combinazioni testo/sfondo, puoi usare la differenza di L come stima affidabile del contrasto percepito.
Una regola pratica:
/* Contrasto elevato: differenza L ≥ 0.5 */
.testo-su-sfondo-scuro {
background: oklch(0.20 0.05 250); /* L = 0.20 */
color: oklch(0.95 0.02 250); /* L = 0.95 — differenza: 0.75 ✅ */
}
/* Contrasto insufficiente: differenza L < 0.3 */
.attenzione {
background: oklch(0.50 0.15 250); /* L = 0.50 */
color: oklch(0.65 0.15 250); /* L = 0.65 — differenza: 0.15 ⚠️ */
}
Questo non sostituisce una verifica WCAG formale, ma offre un’intuizione molto più affidabile di HSL per stimare il contrasto “a occhio” mentre si progetta.
Supporto browser attuale
OKLCH è supportato nativamente in tutti i browser moderni senza prefissi:
- Chrome/Edge: supporto completo da v111 (marzo 2023)
- Firefox: supporto completo da v113 (maggio 2023)
- Safari: supporto completo da v15.4 (marzo 2022) — Safari era in anticipo su tutti
La copertura globale attuale supera il 93% degli utenti. Per i browser legacy ancora in circolazione, la strategia consigliata è un fallback esplicito:
.elemento {
/* Fallback per browser legacy */
color: hsl(220, 70%, 55%);
/* OKLCH per browser moderni */
color: oklch(0.55 0.18 250);
}
Oppure con @supports per logiche più complesse:
@supports (color: oklch(0 0 0)) {
:root {
--primary: oklch(0.55 0.18 250);
}
}
@supports not (color: oklch(0 0 0)) {
:root {
--primary: hsl(220, 70%, 55%);
}
}
Se usi PostCSS, il plugin postcss-oklab-function converte automaticamente oklch() in valori compatibili in fase di build — zero compromessi nel codice sorgente, massima compatibilità in produzione.
Tool e risorse
Editor e picker
- oklch.com — Il picker di riferimento. Permette di esplorare lo spazio OKLCH interattivamente e di copiare i valori CSS direttamente.
- oklch.evilmartians.io — Tool di Evil Martians con generatore di palette integrato.
- Colour & Contrast — Verifica del contrasto WCAG con supporto a OKLCH.
Librerie e integrazioni
- Color.js — Libreria JavaScript completa per conversioni e manipolazioni tra spazi colore, incluso OKLCH. Sviluppata da Lea Verou e Chris Lilley.
- Tailwind CSS v4 — Tailwind ha adottato OKLCH nativamente per la sua palette di default. Se usi Tailwind v4, stai già usando OKLCH.
- postcss-oklab-function — Plugin PostCSS per il fallback automatico.
Letture approfondite
- CSS Color Level 4 — La specifica W3C che definisce OKLCH e gli altri spazi colore moderni.
- “OKLCH in CSS: why we moved from RGB and HSL” — Evil Martians Blog, articolo tecnico di riferimento sull’adozione di OKLCH in produzione.
Conclusione
OKLCH non è solo una sintassi più moderna per scrivere colori in CSS. È un cambio di paradigma nel modo di pensare al colore quando si progetta un’interfaccia.
Con RGB ragionavi in canali fisici. Con HSL ragionavi in tonalità e luminosità — ma quella luminosità era inaffidabile. Con OKLCH ragioni finalmente in termini di come il colore viene percepito: palette coerenti senza aggiustamenti manuali, contrasti prevedibili, design system che si scalano cambiando un singolo valore.
Il supporto browser è ormai maturo, i tool sono eccellenti e l’integrazione con l’ecosistema CSS moderno (variabili, calc(), Tailwind) è nativa.
Se stai costruendo qualcosa oggi, non c’è motivo reale per non iniziare con OKLCH.