Wahrnehmungsgleichmäßigkeit, P3-Gamut und bessere Farbverläufe
oklch() ist der modernste Farbraum in CSS Color Level 4 und löst fundamentale Probleme von hsl() und rgb(): Die Helligkeitsachse ist wahrnehmungsgleichmäßig, Farbverläufe durchqueren keine entsättigten Grautöne, und der Zugang zum P3-Display-Gamut ermöglicht lebhaftere Farben auf modernen Bildschirmen — direkt im Browser, ohne Bildbearbeitungssoftware.
Inhaltsverzeichnis
- 1. Warum hsl() und rgb() an Grenzen stoßen
- 2. oklch() Grundlagen: L, C und H erklärt
- 3. Wahrnehmungsgleichmäßigkeit: was das bedeutet
- 4. P3-Gamut: lebhaftere Farben auf modernen Displays
- 5. Farbverläufe mit oklch(): keine grauen Mittelpunkte
- 6. Design Tokens mit oklch() und Custom Properties
- 7. color-gamut Media Query: P3-Fallbacks richtig einsetzen
- 8. Von hsl() und hex zu oklch() migrieren
- 9. oklch() vs. hsl() im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum hsl() und rgb() an Grenzen stoßen
Die CSS-Farbfunktionen hsl() und rgb() sind seit Jahrzehnten Standard im Web und haben fundamentale Schwächen, die erst durch den Vergleich mit modernen Farbräumen wie dem CSS oklch() Farbraum offensichtlich werden. Das größte Problem von hsl(): Die Helligkeit (L) ist nicht wahrnehmungsgleichmäßig. Zwei Farben mit identischem L-Wert in hsl() erscheinen dem menschlichen Auge unterschiedlich hell, weil das menschliche Sehsystem Farben verschiedener Wellenlängen unterschiedlich hell wahrnimmt. Ein blau-lila Farbton bei hsl(260, 100%, 50%) wirkt deutlich dunkler als ein gelb-grüner Farbton bei hsl(90, 100%, 50%), obwohl beide denselben Helligkeitswert haben.
Das zweite Problem: Der sRGB-Farbraum, in dem hsl() und rgb() operieren, deckt nur einen Teil der Farben ab, die moderne Displays anzeigen können. Displays mit P3-Gamut (alle iPhones seit 2016, alle neueren MacBooks, viele Android-Flaggschiffe) können gesättigtere, lebhaftere Farben darstellen als sRGB erlaubt. Mit hsl() und rgb() sind diese Farben schlicht nicht erreichbar. Der CSS oklch() Farbraum löst beide Probleme gleichzeitig: wahrnehmungsgleichmäßige Achsen und Zugang zu Farben außerhalb des sRGB-Gamuts.
2. oklch() Grundlagen: L, C und H erklärt
Die Funktion CSS oklch() nimmt drei Parameter: L (Lightness, Helligkeit), C (Chroma, Sättigung) und H (Hue, Farbton). Die Helligkeit L reicht von 0 (schwarz) bis 1 (weiß), mit 0,5 als mittleres Grau. Das Besondere: Diese Helligkeitsachse ist wahrnehmungsgleichmäßig kalibriert. Blau bei oklch(0.5 0.2 260) und Gelb bei oklch(0.5 0.15 90) erscheinen dem menschlichen Auge tatsächlich gleich hell – das ist in hsl() nicht der Fall.
Der Chroma-Wert C im CSS oklch() Farbraum ist unbegrenzt – theoretisch kann jede positive Zahl angegeben werden. Praktisch liegen die meisten sRGB-Farben im Bereich 0 bis 0,37. P3-Farben können bis etwa 0,37–0,45 reichen. Werte darüber werden vom Browser auf den darstellbaren Gamut des Displays geclippt. Das bedeutet: Man kann eine Farbe mit oklch(0.7 0.5 290) definieren und der Browser stellt die gesättigteste Version dar, die das Display unterstützt – auf einem P3-Display lebhafter als auf einem sRGB-Display. Der Farbton H folgt demselben 0–360-Grad-Prinzip wie hsl(), aber die Farbverteilung auf dem Kreis ist gleichmäßiger perzeptuell.
/* CSS oklch() color function — L C H syntax */
:root {
/* oklch(lightness chroma hue) */
--color-primary: oklch(0.55 0.22 290); /* vivid purple */
--color-primary-light: oklch(0.80 0.14 290); /* light purple */
--color-primary-dark: oklch(0.35 0.20 290); /* dark purple */
/* Perceptually uniform steps — each step feels equally different */
--blue-100: oklch(0.95 0.05 260);
--blue-300: oklch(0.80 0.10 260);
--blue-500: oklch(0.60 0.18 260);
--blue-700: oklch(0.40 0.15 260);
--blue-900: oklch(0.20 0.08 260);
/* Alpha channel — oklch with alpha */
--overlay: oklch(0.10 0.05 290 / 0.6);
/* Wide-gamut P3 color (exceeds sRGB) */
--accent-vivid: oklch(0.65 0.35 150); /* vivid green, P3-only */
}
.button-primary {
background: var(--color-primary);
color: oklch(0.98 0.01 290);
}
.button-primary:hover {
background: var(--color-primary-dark);
}
3. Wahrnehmungsgleichmäßigkeit: was das bedeutet
Wahrnehmungsgleichmäßigkeit (perceptual uniformity) ist die zentrale Eigenschaft des CSS oklch() Farbraums. Sie bedeutet, dass gleiche numerische Abstände auf der Helligkeitsachse auch gleich großen wahrgenommenen Unterschieden im Auge des Betrachters entsprechen. Das ist eine mathematisch präzise Kalibrierung des Farbraums an das menschliche Sehsystem – und sie macht den Unterschied bei jedem praktischen Einsatz von Farben spürbar. Wenn ein Design-System eine Farbpalette definiert – blau-100, blau-200, bis blau-900 – dann sollen die Helligkeitsstufen gleichmäßig wirken. Mit hsl() scheitert das bei bestimmten Farbtönen systematisch, mit CSS oklch() funktioniert es konsistent.
Ein konkretes Beispiel für die Auswirkung der Wahrnehmungsgleichmäßigkeit: Kontrast-Berechnungen für Accessibility. Um WCAG-konforme Farbkontraste sicherzustellen, muss die wahrgenommene Helligkeit zweier Farben gemessen werden. Berechnungen auf Basis des CSS oklch() Farbraums sind präziser als Berechnungen auf Basis von sRGB, weil die Lightness-Achse bereits wahrnehmungskorrigiert ist. Design-Tokens, die auf CSS oklch() basieren, erzeugen konsistentere Kontrastverhältnisse über verschiedene Farbtöne hinweg – ein klarer Vorteil für barrierefreies Design.
4. P3-Gamut: lebhaftere Farben auf modernen Displays
Der P3-Farbraum (Display P3) deckt etwa 25 Prozent mehr Farben ab als sRGB. Das sind vor allem gesättigtere Grüntöne, leuchtstärkere Orangetöne und intensivere Rottöne, die auf sRGB-Displays nicht darstellbar sind. Auf einem iPhone, einem neueren MacBook oder einem modernen Android-Flaggschiff mit P3-Display sehen diese Farben deutlich lebhafter aus als dieselben Farben in sRGB. Mit dem CSS oklch() Farbraum können diese P3-Farben direkt in CSS definiert werden, indem der Chroma-Wert über den sRGB-Bereich hinaus erhöht wird.
Der Browser handhabt das automatisch korrekt: Auf einem P3-Display werden die lebhafteren Farben angezeigt. Auf einem sRGB-Display werden die Farben auf den darstellbaren sRGB-Gamut geclippt – das Clipping erfolgt dabei möglichst farbnah, so dass die Absicht der Farbe erhalten bleibt. Das bedeutet: Es ist sicher, P3-Farben in CSS oklch() zu definieren, auch wenn nicht alle Nutzer P3-Displays haben. Die sRGB-Nutzer sehen die gesättigtste sRGB-Entsprechung, P3-Nutzer sehen die volle Leuchtkraft. Für bewusste Kontrolle über den Fallback empfiehlt sich die color-gamut Media Query.
/* Wide-gamut colors with oklch — P3 gamut access */
/* sRGB-safe oklch color (C < 0.37 for most hues) */
.badge-safe {
background: oklch(0.55 0.25 290); /* vivid purple, sRGB-compatible */
color: oklch(0.98 0.01 290);
}
/* Wide-gamut P3 color — more vivid on P3 displays */
.badge-vivid {
background: oklch(0.55 0.40 150); /* vivid green, P3 only */
}
/* Explicit P3 gamut control with color() function */
.hero-gradient {
background: linear-gradient(
135deg,
oklch(0.40 0.25 290), /* dark purple */
oklch(0.75 0.35 150) /* vivid green — P3 extended */
);
}
/* CSS color() function for explicit color space */
.p3-accent {
/* display-p3 color space — explicit */
background: color(display-p3 0.2 0.8 0.4);
}
/* Fallback for sRGB displays using @supports */
@supports not (background: oklch(0 0 0)) {
.badge-vivid {
background: hsl(150, 60%, 45%); /* sRGB approximation */
}
}
5. Farbverläufe mit oklch(): keine grauen Mittelpunkte
Einer der sichtbarsten Vorteile des CSS oklch() Farbraums sind Farbverläufe zwischen zwei gesättigten Farben. In hsl() und rgb() führen Verläufe zwischen komplementären Farben (z.B. Blau und Orange) durch einen entsättigten, grauen Mittelpunkt – weil sich die RGB-Kanäle in der Mitte geometrisch zu einem Grauton mitteln. Im CSS oklch() Farbraum bleibt die Sättigung entlang des Verlaufs erhalten. Der Übergang von Blau zu Orange in oklch() führt durch gesättigte Zwischentöne – typischerweise über Grün oder Lila, je nach Richtung – und wirkt dadurch lebendiger und professioneller als dasselbe Gradient in sRGB.
CSS unterstützt ab Level 4 die Angabe des Farbraums für Gradienten direkt in der Funktion: linear-gradient(in oklch, color1, color2). Damit wird der Browser angewiesen, den Verlauf im CSS oklch() Farbraum zu interpolieren statt im sRGB-Standardraum. Das ist einer der wenigen Fälle, in denen der Interpolations-Farbraum explizit gesteuert werden muss – standardmäßig interpoliert der Browser Gradienten in sRGB, selbst wenn die definierten Farben in oklch() angegeben sind.
6. Design Tokens mit oklch() und Custom Properties
Die Kombination aus CSS oklch() und Custom Properties ist der modernste Ansatz für Design-Token-Systeme in CSS. Statt feste Hex-Werte oder hsl()-Werte als Custom Properties zu definieren, werden die drei Achsen von CSS oklch() als separate Custom Properties gespeichert: --brand-l: 0.55, --brand-c: 0.22, --brand-h: 290. Die eigentliche Farbfunktion kombiniert diese Achsen dann zu einer Farbe. Das erlaubt, einzelne Achsen per JavaScript oder in Media Queries anzupassen, ohne die gesamte Farbe neu definieren zu müssen.
Für Dark-Mode-Implementierungen ist dieser Ansatz besonders elegant: Statt für jeden Dark-Mode-Farbton separate Custom Properties zu definieren, kann die Helligkeit --brand-l einfach erhöht werden. oklch(var(--brand-l) var(--brand-c) var(--brand-h)) reagiert dann automatisch korrekt auf die Helligkeitsanpassung. Das funktioniert mit CSS oklch() deutlich besser als mit hsl(), weil die wahrnehmungsgleichmäßige Helligkeitsachse sicherstellt, dass alle Farbtöne im Dark Mode gleich hell wirken – und nicht wie im hsl()-Fall einige Farbtöne bei derselben Helligkeit viel dunkler oder heller erscheinen.
/* Design token system with oklch Custom Properties */
:root {
/* Brand color axes as separate tokens */
--brand-l: 0.55;
--brand-c: 0.22;
--brand-h: 290;
/* Composed color from axes */
--color-brand: oklch(var(--brand-l) var(--brand-c) var(--brand-h));
--color-brand-hover: oklch(calc(var(--brand-l) - 0.1) var(--brand-c) var(--brand-h));
--color-brand-muted: oklch(var(--brand-l) calc(var(--brand-c) * 0.4) var(--brand-h));
}
/* Dark mode: adjust lightness axis only */
@media (prefers-color-scheme: dark) {
:root {
--brand-l: 0.75; /* lighter in dark mode */
}
}
/* Palette generation — uniform perceptual steps */
:root {
--violet-1: oklch(0.97 0.03 290);
--violet-2: oklch(0.92 0.06 290);
--violet-3: oklch(0.83 0.10 290);
--violet-4: oklch(0.72 0.16 290);
--violet-5: oklch(0.60 0.22 290);
--violet-6: oklch(0.47 0.22 290);
--violet-7: oklch(0.36 0.18 290);
--violet-8: oklch(0.25 0.13 290);
--violet-9: oklch(0.15 0.07 290);
}
/* oklch gradient with explicit interpolation space */
.hero-bg {
background: linear-gradient(
in oklch 135deg,
oklch(0.25 0.20 290),
oklch(0.65 0.30 200)
);
}
7. color-gamut Media Query: P3-Fallbacks richtig einsetzen
Die @media (color-gamut: p3) Media Query ermöglicht es, P3-Farben gezielt nur auf Displays anzuwenden, die den P3-Gamut unterstützen. Das ist die empfohlene Methode, um P3-Farben einzusetzen, ohne dass sRGB-Displays abrupte Farbclipping-Artefakte sehen. Der Grundansatz: Basis-Styles mit sRGB-kompatiblen CSS oklch() Farben definieren, dann innerhalb der color-gamut: p3 Media Query die gesättigteren P3-Varianten überschreiben. Das ist präziser als die @supports-Methode, da ein Browser CSS oklch() unterstützen kann, ohne ein P3-Display zu haben.
In der Praxis ist die Unterscheidung subtiler: Browser clippen P3-Farben auf sRGB-Displays automatisch und möglichst farbtreu. Das Clipping ist in den meisten Fällen gut genug, so dass explizite color-gamut-Fallbacks nur bei Farben nötig sind, bei denen das Clipping den Designintent stark verfälscht – etwa bei sehr gesättigten Grüntönen, die nach Clipping deutlich gräulicher wirken. Für normale Designarbeit mit dem CSS oklch() Farbraum kann man die automatische Browser-Gamut-Kompression nutzen und hat trotzdem ein besseres Ergebnis als mit reinem sRGB.
8. Von hsl() und hex zu oklch() migrieren
Die Migration bestehender CSS-Farbpaletten zum CSS oklch() Farbraum ist keine direkte numerische Umrechnung, sondern eine visuelle Neuinterpretation. Die Konvertierung von hsl(260, 70%, 50%) zu CSS oklch() ergibt andere Zahlenwerte, aber eine wahrnehmungsmäßig ähnliche Farbe. Online-Tools wie die oklch Picker von Björn Ottosson oder das oklch.com-Tool zeigen die CSS oklch()-Entsprechung für jede sRGB-Farbe an. Programmatisch gibt es Konverter-Bibliotheken in JavaScript und Python, die die Umrechnung über den Linear-sRGB-Zwischenraum durchführen.
Der sinnvolle Migrationsweg ist nicht, jede einzelne Farbe zu konvertieren, sondern das System neu zu definieren. Die Brand-Farben werden in CSS oklch() neu kalibriert – mit gleichmäßigen Helligkeitsabständen zwischen den Palettenstufen statt der oft ungleichmäßigen Abstände in legacy hsl()-Paletten. Das Ergebnis ist eine Farbpalette, die sowohl auf sRGB-Displays als auch auf P3-Displays gut aussieht, bessere Kontrastverhältnisse hat und leichter in Custom Properties für Dark Mode und Themes manipulierbar ist. Die einmalige Investition in die Neukalibration der Palette zahlt sich durch bessere visuelle Konsistenz und einfachere Wartung aus.
| Eigenschaft | hsl() | oklch() | Vorteil oklch() |
|---|---|---|---|
| Helligkeitsachse | Nicht wahrnehmungsgleichmäßig | Wahrnehmungsgleichmäßig | Konsistente Farbstufen-Abstände |
| Gamut | Nur sRGB | sRGB + P3 + Rec2020 | Lebhaftere Farben auf P3-Displays |
| Gradienten-Mittelpunkt | Oft grau / entsättigt | Gesättigt und lebendig | Visuell hochwertigere Verläufe |
| Dark Mode Anpassung | Ungleichmäßige Ergebnisse | Vorhersehbar durch L-Achse | Einfachere Design-Token-Logik |
| Browser-Support 2026 | Alle Browser, inkl. IE | Alle modernen Browser (93%+) | Fallback mit @supports sinnvoll |
9. oklch() vs. hsl() im direkten Vergleich
Der direkteste Vergleich zwischen CSS oklch() und hsl() zeigt sich bei der Definition einer Farbpalette. Eine sRGB-Palette in hsl() mit gleichmäßig gestuften Helligkeitswerten (10%, 20%, 30%, ..., 90%) erzeugt Farbtöne, die visuell ungleichmäßig wirken – bestimmte Farbwerte erscheinen viel heller oder dunkler als ihr numerischer Helligkeitswert suggeriert. Eine CSS oklch()-Palette mit gleichmäßig gestuften L-Werten (0.1, 0.2, ..., 0.9) erzeugt Farbtöne, die dem Auge tatsächlich als gleichmäßig abgestuft erscheinen, unabhängig vom Farbton.
Das zweite wichtige Unterscheidungsmerkmal ist die Farbsattheit bei Helligkeitsanpassungen. In hsl() bleibt die Sättigung konstant, wenn man die Helligkeit ändert – aber die wahrgenommene Sättigung ändert sich dennoch erheblich, weil Helligkeit und Sättigung in hsl() nicht unabhängig von der menschlichen Wahrnehmung sind. Im CSS oklch() Farbraum ist die Chroma-Achse (C) tatsächlich unabhängig von der Lightness-Achse. Eine Farbe mit konstantem C und variierendem L ändert ihre wahrgenommene Leuchtkraft, ohne die wahrgenommene Reinheit der Farbe zu verändern – was vorhersehbare, sauberere Farbsysteme ermöglicht.
Mironsoft
Design-Tokens, CSS-Farbsysteme und Frontend-Architektur
Farbsystem mit oklch() und Design Tokens aufbauen?
Wir entwickeln moderne CSS-Farbsysteme auf Basis von oklch(), Custom Properties und @layer — wahrnehmungsgleichmäßige Paletten, P3-Unterstützung und automatischer Dark Mode ohne manuelle Farbwert-Kalibration.
Farbsystem-Audit
Analyse bestehender hsl()/hex-Paletten auf Konsistenz und Kontrastkriteria
oklch()-Palette
Neuaufbau des Farbsystems mit oklch() und wahrnehmungsgleichmäßigen Stufen
Dark Mode
Automatischer Dark Mode über oklch()-Lightness-Achse in Custom Properties
10. Zusammenfassung
Der CSS oklch() Farbraum ist 2026 in allen modernen Browsern vollständig unterstützt und bietet drei fundamentale Vorteile gegenüber hsl() und rgb(): eine wahrnehmungsgleichmäßige Helligkeitsachse für konsistente Farbpaletten, Zugang zum P3-Gamut für lebhaftere Farben auf modernen Displays und bessere Farbverlauf-Interpolation ohne entsättigte Mittelpunkte. Die Kombination mit CSS Custom Properties erlaubt elegante Design-Token-Systeme, bei denen einzelne Achsen (Lightness, Chroma, Hue) separat manipuliert werden können – perfekt für Dark-Mode-Implementierungen.
Die Migration von hsl() und Hex-Farben zum CSS oklch() Farbraum ist eine Investition, die sich durch bessere visuelle Konsistenz, einfachere Wartung und zukunftssichere Farbpaletten auszahlt. Explizite P3-Fallbacks sind mit der color-gamut Media Query möglich, aber das automatische Browser-Gamut-Clipping ist für die meisten Anwendungsfälle ausreichend. @supports (background: oklch(0 0 0)) liefert bei Bedarf einen präzisen Fallback für Browser ohne CSS oklch()-Support.
CSS oklch() Farbraum — Das Wichtigste auf einen Blick
L C H Achsen
L = Lightness (0–1), C = Chroma (0–0.4+), H = Hue (0–360). Lightness ist wahrnehmungsgleichmäßig kalibriert.
P3-Gamut
Chroma über 0.37 verlässt sRGB. Browser clippt automatisch auf Display-Gamut. color-gamut: p3 für explizite Kontrolle.
Design Tokens
L, C, H als separate Custom Properties. Dann oklch(var(--l) var(--c) var(--h)). Dark Mode via --l-Anpassung in @media.
Browser-Support 2026
Chrome 111+, Firefox 113+, Safari 15.4+. @supports (background: oklch(0 0 0)) für Fallback. Global 93%+.