Farbtöne direkt aus vorhandenen CSS-Variablen ableiten
Die Relative Color Syntax erlaubt es, aus einer einzigen Markenfarbe im Browser eine vollständige Palette zu berechnen, statt Hover, Active und Rahmenfarben als eigene Variablen zu pflegen. Mit dem Schlüsselwort from, Farbraum-Kanälen und calc() entstehen wartbare Farbsysteme direkt in nativem CSS, ganz ohne Sass oder Build-Schritt.
Inhaltsverzeichnis
- 1. Was Relative Color Syntax löst
- 2. Syntax im Detail: from, Kanäle und calc()
- 3. Hover und Active Zustände aus einer Basisfarbe ableiten
- 4. Kombination mit oklch für gleichmäßige Abstufungen
- 5. Alpha-Kanal-Manipulation ohne zusätzliche Variable
- 6. Praxisbeispiel: komplette Palette aus einer Markenfarbe
- 7. Browser-Unterstützung, Fallbacks und @supports
- 8. Wartbarkeit im Vergleich zu Sass-Funktionen
- 9. Relative Color Syntax im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Was Relative Color Syntax löst
Die Relative Color Syntax ist Teil des CSS Color Module Level 5 und beantwortet ein Problem, das in jedem größeren Stylesheet auftaucht: Aus einer definierten Basisfarbe müssen Varianten für Hover, Active, Fokus-Ringe und Rahmen entstehen, ohne dass jede Variante als eigene Custom Property gepflegt werden muss. Vor der Relative Color Syntax gab es dafür nur zwei Wege, entweder einen Präprozessor wie Sass mit Funktionen wie darken() und lighten() einzusetzen, oder für jede Variante eine eigene Hex- oder OKLCH-Variable von Hand zu berechnen und zu pflegen.
Beide Wege erzeugen Wartungsaufwand. Ändert sich die Markenfarbe, müssen bei der manuellen Variante alle abgeleiteten Werte neu berechnet werden. Bei Sass entsteht zusätzlich ein Build-Schritt, der zur Laufzeit im Browser nicht mehr veränderbar ist, was Theming per JavaScript oder per prefers-color-scheme erschwert. Die Relative Color Syntax löst genau das: Die Ableitung passiert direkt im Browser, zur Laufzeit, aus dem aktuellen Wert einer beliebigen Farbe, egal ob sie als Custom Property, als Literal oder als Ergebnis einer weiteren Farbfunktion vorliegt.
2. Syntax im Detail: from, Kanäle und calc()
Die Grundform der Relative Color Syntax sieht so aus: oklch(from <farbe> l c h). Das Schlüsselwort from gefolgt von einer beliebigen Farbe öffnet den Zugriff auf deren Kanäle im Zielfarbraum. Bei oklch() sind das l für Lightness, c für Chroma und h für Hue, jeweils unter demselben Namen wie im Funktionsaufruf ansprechbar. Wird ein Kanal unverändert übernommen, schreibt man einfach seinen Namen, soll er verändert werden, ersetzt man ihn durch einen berechneten Ausdruck oder direkt durch calc().
Wichtig ist, dass die Quellfarbe in jedem beliebigen Format vorliegen darf, etwa als Hex-Wert, als rgb(), als hsl() oder als weitere Relative Color Syntax-Berechnung, während der Zielfarbraum in der äußeren Funktion bestimmt, mit welchen Kanalnamen gearbeitet wird. Das erlaubt sogar Farbraum-Konvertierung als Nebeneffekt, aus einer als Hex definierten Farbe können mit oklch(from #7c3aed l c h) direkt deren OKLCH-Kanäle gelesen werden, ganz ohne externes Konvertierungstool.
/* Basic Relative Color Syntax: read channels from an existing color */
:root {
--brand: #7c3aed;
}
.button {
/* Convert hex to oklch and read its channels directly */
background: oklch(from var(--brand) l c h);
}
.button:hover {
/* Reduce lightness by an absolute amount using calc() */
background: oklch(from var(--brand) calc(l - 0.08) c h);
}
.button:active {
/* Reduce lightness further, slightly desaturate too */
background: oklch(from var(--brand) calc(l - 0.14) calc(c * 0.9) h);
}
Ein häufiger Stolperstein bei diesem Muster: l in oklch() ist auf den Bereich 0 bis 1 normiert, während manche Tools Lightness als Prozentwert von 0 bis 100 ausgeben. Wer mit calc(l - 8%) rechnet, statt mit calc(l - 0.08), erhält ein völlig anderes Ergebnis oder einen ungültigen Wert. Die Relative Color Syntax unterstützt zwar auch Prozentangaben für l, c und h in manchen Kontexten, konsistent und vorhersehbar bleibt aber nur, wer sich pro Farbraum an eine Einheit hält und diese im Team dokumentiert.
3. Hover und Active Zustände aus einer Basisfarbe ableiten
Der häufigste praktische Einsatz der Relative Color Syntax ist genau das Beispiel aus dem letzten Abschnitt: interaktive Zustände einer Komponente aus ihrer Basisfarbe ableiten. Statt für jeden Button drei bis vier Variablen zu pflegen, reicht eine einzige Custom Property, aus der Hover, Active, Fokus und Disabled berechnet werden. Das reduziert nicht nur die Anzahl der Variablen, sondern garantiert auch, dass alle Zustände tatsächlich zur Basisfarbe passen, weil sie mathematisch aus ihr abgeleitet sind, statt unabhängig von Hand gepflegt zu werden.
Besonders wertvoll wird das in Komponenten-Bibliotheken mit vielen Farbvarianten, etwa einem Button, der als primary, danger, success oder warning existiert. Statt für jede Variante ein komplettes Set an Zustandsfarben zu definieren, definiert man nur die Basisfarbe pro Variante und lässt alle Zustände über dieselbe Relative Color Syntax-Formel berechnen. Ändert sich später der gewünschte Kontrast für Hover-Zustände insgesamt, genügt eine Anpassung der Formel an einer zentralen Stelle, statt Dutzende Einzelwerte zu korrigieren.
4. Kombination mit oklch für gleichmäßige Abstufungen
Die Relative Color Syntax entfaltet ihr volles Potenzial in Kombination mit dem oklch()-Farbraum, weil dessen Lightness-Achse wahrnehmungsgleichmäßig ist. Eine Reduktion von l um denselben Betrag wirkt bei jeder Ausgangsfarbe gleich stark dunkler, unabhängig davon, ob die Basisfarbe Blau, Gelb oder Violett ist. Bei hsl() ist das nicht der Fall, dort erzeugt dieselbe Lightness-Reduktion je nach Farbton unterschiedlich stark wahrgenommene Helligkeitsunterschiede, weil hsl() nicht auf menschlicher Farbwahrnehmung, sondern auf einem einfachen zylindrischen RGB-Modell basiert.
In der Praxis bedeutet das: Eine mit Relative Color Syntax und oklch() gebaute Abstufungsformel funktioniert für jede beliebige Markenfarbe gleich gut, ohne dass für jede Farbe individuell nachjustiert werden muss. Das ist der entscheidende Vorteil gegenüber älteren Sass-Funktionen wie darken(), die intern häufig auf hsl() aufbauen und deshalb bei manchen Farbtönen zu unerwartet starken oder schwachen Kontrasten führen.
/* Perceptually uniform tint and shade scale from one base color */
:root {
--brand-500: oklch(58% 0.19 291);
}
.card {
/* Consistent lightness steps regardless of hue */
--brand-100: oklch(from var(--brand-500) 0.94 calc(c * 0.35) h);
--brand-300: oklch(from var(--brand-500) 0.80 calc(c * 0.7) h);
--brand-700: oklch(from var(--brand-500) calc(l - 0.16) c h);
--brand-900: oklch(from var(--brand-500) calc(l - 0.32) calc(c * 0.6) h);
background: var(--brand-100);
border: 1px solid var(--brand-300);
color: var(--brand-900);
}
5. Alpha-Kanal-Manipulation ohne zusätzliche Variable
Neben Lightness, Chroma und Hue erlaubt die Relative Color Syntax auch den direkten Zugriff auf den Alpha-Kanal über den Namen alpha. Das macht es überflüssig, für transparente Varianten einer Farbe eine zweite Custom Property in rgba- oder Farbfunktions-Notation zu pflegen. Statt --brand-transparent: rgba(124, 58, 237, 0.15) als eigene, potenziell aus dem Sync geratene Variable zu definieren, berechnet man den transparenten Wert direkt aus der Basisfarbe.
Das ist besonders nützlich für Overlay-Hintergründe, Fokus-Ringe und subtile Trennlinien, die alle denselben Farbton wie die Basisfarbe tragen sollen, aber mit unterschiedlicher Deckkraft. Mit der Relative Color Syntax bleibt die Beziehung zwischen Basisfarbe und ihren transparenten Varianten immer explizit im Code sichtbar, statt implizit über zwei unabhängig gepflegte Variablen zu bestehen, die bei einer Änderung der Basisfarbe leicht auseinanderlaufen.
/* Alpha channel access via Relative Color Syntax */
:root {
--focus-color: oklch(62% 0.21 264);
}
.input:focus-visible {
outline: 2px solid var(--focus-color);
/* Same hue, reduced opacity, no second variable required */
box-shadow: 0 0 0 4px oklch(from var(--focus-color) l c h / 0.25);
}
.overlay {
/* Derive a translucent backdrop directly from the brand color */
background: oklch(from var(--brand-500) calc(l - 0.4) c h / 0.55);
}
6. Praxisbeispiel: komplette Palette aus einer Markenfarbe
In einem realen Design-System-Projekt lässt sich die Relative Color Syntax nutzen, um aus genau einer Markenfarbe eine zehnstufige Palette zu erzeugen, ähnlich den Skalen von Tailwind CSS, aber ohne vorab generierte statische Werte. Der Vorteil gegenüber einer fest im Buildprozess erzeugten Palette: Ändert sich die Markenfarbe während eines Rebrandings, muss lediglich die eine Basisvariable angepasst werden, alle abgeleiteten Stufen aktualisieren sich automatisch, ganz ohne erneuten Build.
Diese Technik eignet sich hervorragend für Multi-Tenant-Anwendungen, in denen jeder Kunde seine eigene Markenfarbe hinterlegt. Statt für jeden Kunden eine komplette Palette zu berechnen und als CSS-Datei auszuliefern, genügt eine einzige Custom Property pro Tenant plus eine gemeinsam genutzte Relative Color Syntax-Formel, die für jeden Tenant automatisch die passenden Abstufungen erzeugt.
/* Ten-step palette derived from a single tenant brand color */
:root {
--tenant-brand: oklch(55% 0.20 258);
--color-50: oklch(from var(--tenant-brand) 0.97 calc(c * 0.15) h);
--color-100: oklch(from var(--tenant-brand) 0.93 calc(c * 0.3) h);
--color-300: oklch(from var(--tenant-brand) 0.82 calc(c * 0.65) h);
--color-500: var(--tenant-brand);
--color-700: oklch(from var(--tenant-brand) calc(l - 0.14) c h);
--color-900: oklch(from var(--tenant-brand) calc(l - 0.30) calc(c * 0.7) h);
}
7. Browser-Unterstützung, Fallbacks und @supports
Chrome, Edge und Safari unterstützen die Relative Color Syntax seit 2023 beziehungsweise 2024 vollständig, Firefox zog mit Version 128 nach. Für Projekte, die noch ältere Browser bedienen müssen, empfiehlt sich ein Fallback über @supports, bei dem außerhalb des unterstützten Blocks feste Hex- oder OKLCH-Werte als statische Reserve dienen. Wichtig dabei: @supports (color: oklch(from red l c h)) prüft konkret die Relative-Color-Syntax-Fähigkeit, nicht nur die generelle oklch()-Unterstützung, da manche Browser oklch() ohne from bereits früher implementiert hatten.
In der Praxis reicht dieser Fallback meist aus: Alte Browser sehen eine solide, manuell gepflegte Basispalette, moderne Browser bekommen die dynamisch berechnete Version mit allen Vorteilen der Relative Color Syntax. Da Farbabstufungen selten geschäftskritisch sind, ist ein optisch leicht abweichender, aber funktional korrekter Fallback in den allermeisten Projekten ein akzeptabler Kompromiss.
/* Fallback for browsers without Relative Color Syntax support */
.button {
background: #6d28d9; /* static fallback shade */
}
@supports (color: oklch(from red l c h)) {
.button {
background: oklch(from var(--brand-500) l c h);
}
.button:hover {
background: oklch(from var(--brand-500) calc(l - 0.08) c h);
}
}
8. Wartbarkeit im Vergleich zu Sass-Funktionen
Sass-Funktionen wie darken(), lighten() und mix() galten jahrelang als Standardlösung für abgeleitete Farben, haben aber einen strukturellen Nachteil: Sie werden zur Build-Zeit ausgewertet und erzeugen statische Werte im ausgelieferten CSS. Ein Theme-Wechsel zur Laufzeit, etwa über prefers-color-scheme oder einen manuellen Dark-Mode-Toggle, kann diese Werte nicht mehr beeinflussen, weil sie bereits fest im Stylesheet stehen. Die Relative Color Syntax löst genau dieses Problem, weil die Berechnung im Browser passiert und automatisch neu ausgewertet wird, sobald sich die referenzierte Custom Property ändert.
Ein weiterer Vorteil: Mit der Relative Color Syntax entfällt die Abhängigkeit von einem Build-Tool für reine Farbberechnungen. Kleinere Projekte ohne Sass-Toolchain profitieren besonders, weil sie dieselbe Funktionalität nun in reinem CSS erreichen, ohne node-sass, Dart Sass oder einen zusätzlichen PostCSS-Schritt einzuführen. Für Design-Systeme, die ohnehin auf Custom Properties setzen, ist die Relative Color Syntax damit die konsequente native Weiterentwicklung.
9. Relative Color Syntax im direkten Vergleich
Die folgende Tabelle stellt die drei gängigen Ansätze zur Farbableitung gegenüber und zeigt, wann welcher Ansatz die bessere Wahl ist.
| Kriterium | Sass darken/lighten | Relative Color Syntax | Manuelle Variablen |
|---|---|---|---|
| Laufzeit-Update | Nein, statisch | Ja, live im Browser | Nein, manuell |
| Build-Schritt nötig | Ja | Nein | Nein |
| Wahrnehmungsgleichmäßig | Selten (hsl-basiert) | Ja, mit oklch | Abhängig vom Ersteller |
| Anzahl Variablen | Gering | Minimal | Hoch |
| Browser-Support 2026 | Nicht relevant (Build-Zeit) | Alle modernen Engines | Universell |
In neuen Projekten mit modernem Browser-Ziel ist die Relative Color Syntax fast immer die richtige Wahl, weil sie Build-Abhängigkeiten reduziert und gleichzeitig Laufzeit-Theming ermöglicht. Bestehende Projekte mit ausgereifter Sass-Toolchain müssen nicht sofort migrieren, sollten aber neue Farbfunktionen bevorzugt mit der Relative Color Syntax aufbauen, um schrittweise unabhängiger von der Build-Zeit-Berechnung zu werden.
Mironsoft
CSS-Architektur, Design Tokens und moderne Farbsysteme
Eine Farbpalette, die sich selbst pflegt?
Wir bauen Farbsysteme mit Relative Color Syntax und oklch, die aus einer einzigen Markenfarbe pro Tenant automatisch konsistente, wahrnehmungsgleichmäßige Paletten ableiten, ganz ohne Build-Schritt und ohne doppelte Wartung.
Farbsystem-Audit
Bestehende Variablen und Sass-Funktionen auf Relative Color Syntax migrieren
Design Tokens
Skalierbare Token-Architektur mit oklch und Relative Color Syntax aufbauen
Multi-Tenant-Theming
Pro Kunde nur eine Basisfarbe, alle Abstufungen automatisch berechnet
10. Zusammenfassung
Die Relative Color Syntax verändert, wie Farbsysteme in CSS aufgebaut werden. Statt für jede Variante einer Farbe eine eigene Custom Property zu pflegen, wird aus einer einzigen Basisfarbe mit from, Farbraum-Kanälen und calc() alles Weitere zur Laufzeit im Browser berechnet. Kombiniert mit oklch() entstehen wahrnehmungsgleichmäßige Abstufungen, die für jede Markenfarbe gleich gut funktionieren, ohne manuelles Nachjustieren pro Farbton.
Der größte praktische Gewinn zeigt sich in Design-Systemen und Multi-Tenant-Anwendungen, wo aus einer einzigen Variable pro Marke automatisch komplette Paletten inklusive Hover-, Active- und transparenten Zuständen entstehen. Mit einem @supports-Fallback lässt sich die Relative Color Syntax bereits heute produktiv einsetzen, während ältere Browser eine statische Reservefarbe erhalten.
Relative Color Syntax praktisch nutzen — Das Wichtigste auf einen Blick
Grundsyntax
oklch(from var(--brand) l c h) liest Kanäle einer beliebigen Farbe aus und erlaubt gezielte Anpassung einzelner Werte.
Mit oklch kombinieren
Wahrnehmungsgleichmäßige Lightness-Achse macht Abstufungsformeln unabhängig vom konkreten Farbton.
Alpha-Kanal
Transparente Varianten direkt aus der Basisfarbe ableiten, ohne zweite Variable in rgba-Notation.
Fallback
@supports (color: oklch(from red l c h)) liefert alten Browsern eine statische Reservefarbe.