Farbe/Relative Farbangaben
Bisher gab es nur feste Farbangaben, z.B. ein RGB-Wert für den Hintergrund. Wenn man eine dunklere Schattierung benötigte, musste dies in einem Grafikprogramm oder Farbwähler ermittelt und dann wieder als fester Wert eingegeben werden.
Dieses Tutorial zeigt, wie Du dies nun bequem mit den neuen Funktionen des CSS Color Module Level 5[1] nur im CSS erledigen kannst!
Achtung!
Es gibt einen Polyfill von Evil Martians, alternativ müsste man die errechneten Farbwerte einmal manuell in HEX-Werte umrechnen.
--Matthias Scharwies (Diskussion) 13:11, 11. Juli 2024 (CET)Inhaltsverzeichnis
relative Farbangaben
Bisher mussten alle Farben einer Farbpalette in einem Grafikprogramm berechnet und festgelegt werden. So kamen für eine Grund- und mehrere Akzentfarben schnell viele Farben zusammen.
Mit der relativen Farbsyntax[2] können Grund- und Akzentfarben in einem beliebigen Farbraum oder einer beliebigen Syntax und entsprechende Varianten mit viel weniger Code erstellt werden.[3]
Schlüsselwort from
In diesem Beispiel aus der Spec wird eine Farbe um eine durchscheinende Variante für ein Overlay erweitert:
:root { --bg-color: blue; }
.overlay {
background: rgb(from var(--bg-color) r g b / 50%);
}
-
var(--bg-color)
-
rgb(from var(--bg-color) r g b / 50%)
Als Standard-Hintergrundfarbe wird Blau in der custom property --bg-color:blue
festgelegt.
Für die Klasse overlay
wird nun eine rgb()-Funktion aufgerufen, die über das Schlüsselwort from
die entsprechende Farbfestlegung aufnimmt. Die r-, g- und b-Kanäle der Ursprungsfarbe bleiben unverändert, indem sie mit den Schlüsselwörtern angegeben werden, die ihre Werte von der Ursprungsfarbe ableiten. Zusätzlich wird aber die Deckkraft auf 50 % gesetzt, um sie transparent zu machen, unabhängig davon, wie hoch die Deckkraft der Ursprungsfarbe war.
Rechenoperationen
:root { --bg-color: green; }
.foo {
--darker-accent: oklch(from var(--bg-color) calc(l / 2) c h);
}
-
var(--bg-color)
-
oklch(from var(--bg-color) calc(l / 2) c h)
In diesem Beispiel wird die Ursprungsfarbe abgedunkelt, indem ihre Helligkeit halbiert wird, ohne irgendeinen anderen Aspekt der Farbe zu verändern.
Dabei wird die vorher festgelegte custom property --bgcolor
durch from
als Basisfarbe festgelegt. Während der 2. und 3, Parameter c und h unverändert bleiben, wird die Hellligkeit l durch eine calc()-Funktion verändert.
oklch()
-Funktion verwendet wird.Farbänderung
:root { --bg-color: lime; }
.error {
-background: oklch(from var(--bg-color) calc(l * 0.5) c 30);
}
-
var(--bg-color)
-
oklch(from var(--bg-color) calc(l * 0.5) c 30)
Die Hintergrundfarbe ist ein knalliges Grün, für Fehlermeldungen, wird der Farbton (Hue) auf einen Wert von 30(°) gesetzt.
eine eigene Farbpalette erstellen
Dies wollen wir nun für eine eigene Farbpalette nutzen:
Ausgangspunkt sind unsere SELF-Farben Gelb und Blau, die durch einen Rot-Ton als Signalfarbe ergänzt werden sollen:
-
oklch(50% 0.1 240)
SELF-Blau -
oklch(50% 0.16 90)
-
oklch(75% 0.16 90)
SELF-Gelb
-
oklch(50% 0.16 30)
Rot als Akzent für Warnungen -
oklch(50% 0.16 120)
Grün als Akzent für Tipps und Empfehlungen
:root {
--brand-color: oklch(50% 0.1 240);
--accent1-clr: oklch(75% 0.16 90);
--accent2-clr: oklch(50% 0.16 30);
--accent3-clr: oklch(50% 0.16 120);
}
Das Blau soll nun in Schattierungen aufgehellt und abgedunkelt werden:
:root {
--brand-color-darkest: oklch(from var(--brand-color) 16% c h);
--brand-color-darker: oklch(from var(--brand-color) 28% c h);
--brand-color-dark: oklch(from var(--brand-color) 40% c h);
--brand-color: oklch(50% 0.1 240);
--brand-color-light: oklch(from var(--brand-color) 70% c h);
--brand-color-lighter: oklch(from var(--brand-color) 82% c h);
--brand-color-lightest: oklch(from var(--brand-color) 93% c h);
}
-
oklch(from var(--brand-color) 16% c h)
-
oklch(from var(--brand-color) 28% c h)
-
oklch(from var(--brand-color) 40% c h)
-
oklch(50% 0.1 240)
-
oklch(from var(--brand-color) 70% c h)
-
oklch(from var(--brand-color) 82% c h)
-
oklch(from var(--brand-color) 94% c h)
Ergebnis
Schöner wäre es, wenn die Schattierung als custom property auch anderen Farben zur Verfügung stehen würde:
--dk2: -.30;
--dk1: -.16;
--dk: -0.08;
--li2: 0.5;
--li1: 0.35;
--li: 0.2;
-
oklch(from var(--blu) calc(l + var(--dk2)) c h)
-
oklch(from var(--blu) calc(l + var(--dk1)) c h)
-
oklch(from var(--blu) calc(l + var(--dk)) c h)
-
oklch(50% 0.1 240)
-
oklch(from var(--blu) calc(l + var(--li)) c h)
-
oklch(from var(--blu) calc(l + var(--li1)) c h)
-
oklch(from var(--blu) calc(l + var(--li2)) c h)
-
oklch(from var(--yel) calc(l + var(--dk2)) c h)
-
oklch(from var(--yel) calc(l + var(--dk1)) c h)
-
oklch(from var(--yel) calc(l + var(--dk)) c h)
-
oklch(50% 0.16 90)
-
oklch(from var(--yel) calc(l + var(--li)) c h)
-
oklch(from var(--yel) calc(l + var(--li1)) c h)
-
oklch(from var(--yel) calc(l + var(--li2)) c h)
-
oklch(from var(--red) calc(l + var(--dk2)) c h)
-
oklch(from var(--red) calc(l + var(--dk1)) c h)
-
oklch(from var(--red) calc(l + var(--dk)) c h)
-
oklch(50% 0.16 30)
-
oklch(from var(--red) calc(l + var(--li)) c h)
-
oklch(from var(--red) calc(l + var(--li1)) c h)
-
oklch(from var(--red) calc(l + var(--li2)) c h)
-
oklch(from var(--gre) calc(l + var(--dk2)) c h)
-
oklch(from var(--gre) calc(l + var(--dk1)) c h)
-
oklch(from var(--gre) calc(l + var(--dk)) c h)
-
oklch(50% 0.16 120)
-
oklch(from var(--gre) calc(l + var(--li)) c h)
-
oklch(from var(--gre) calc(l + var(--li1)) c h)
-
oklch(from var(--gre) calc(l + var(--li2)) c h)
Information: Redaktionelles
Um diese Farbpaletten in zwei Spalten zu „zwingen“, habe ich Namen der custom properties so kurz wie möglich gefasst. Im Normalfall wäre ein Sprechender Variablenname besser.
--Matthias Scharwies (Diskussion) 10:15, 17. Jan. 2024 (CET)Die Signalfarbe Gelb soll zusätzlich zu den unterschiedlichen Helligkeitsstufen auch eine andere Chroma erhalten:
:root {
--yel-dk1: oklch(28% 0.1 90);
--yel-dk: oklch(40% 0.15 90);
--yel: oklch(75% 0.2 90);
--yel-li: oklch(82% 0.15 90);
--yel-li1: oklch(89% 0.1 90);
--yel-li2: oklch(96% 0.05 90);
}
-
oklch(28% 0.1 90)
-
oklch(40% 0.15 90)
-
oklch(75% 0.2 90)
-
oklch(82% 0.15 90)
-
oklch(89% 0.1 90)
-
oklch(96% 0.05 90)
Textfarben mit hohem Kontrast
Früher musst man im nächsten Schritt zu jeder Hintergrundfarbe passende Schriftfarben suchen und dann den Kontrast testen. Jetzt schafft dies CSS ganz alleine:
Alle Grundfarben unserer Palette haben die gleiche wahrgenommene Helligkeit.
Information: Farbumkehr
.invert-each-rgb-channel { background: rgb(from yellow calc(1 - r) calc(1 - g) calc(1 - b)); }Das Erzeugen einer Komplementärfarbe hilft hier nur bedingt. So hat gerade grün und rot einen zu geringen Kontrast. Eine gute Lesbarkeit erreicht man durch hohen Kontrast, z.B. durch große Helligkeitsunterschiede.
Im folgenden Beispiel werden für dunkle Farbtöne helle Schriftfarben, für helle Hintergründe entsprechend dunklere Varienten erzeugt:[4]
.info {
color: var(--color-primary);
background-color: oklch(from var(--color-primary) calc(l + 45) calc(c *0.5) h);
h2 {
background-color: var(--color-primary);
color: oklch(from var(--color-primary) calc(l + 40) c h);
}
}
.warning {
color: var(--color-secondary);
background-color: oklch(from var(--color-secondary) calc(l + 45) c h);
h2 {
background-color: var(--color-secondary);
color: oklch(from var(--color-secondary) calc(l + 60) c h);
}
}
button {
background-color: var(--color-accent);
color: oklch(from var(--color-accent) calc(l - 50) c h);
}
color-mix() als Fallback
Nutzer älterer Browser sehen bei den oben gezeigten Farbfeldern mit relativen Farbangaben nur weiße Kästchen.Mit der color-mix()-Funktion kann man dies umgehen:
color-mix(method, color1[ p1], color2[ p2])
Das Schlüsselwort in leitet einen Farbraum ein, in dem die Farbmischung erzeugt werden soll.
Danach folgen zwei Farbangaben, optional ergänzt durch eine Prozentangabe:
-
color-mix(in oklch, red, yellow)
-
color-mix(in oklch, red 30%, blue )
-
color-mix(in srgb, #337599 80%, white)
-
color-mix(in oklch longer hue, #337599 60%, white)
[5]
Farbinterpolation
Zwischen zwei Farben einen Übergang zu ermitteln – zu interpolieren – ist eine Aufgabe, die CSS an verschiedenen Stellen lösen muss.
- Animieren von Farben mit transition oder animation
- Erstellen von Gradienten
- Anwenden von Filtern
- Berechnen einer Mischfarbe mit color-mix()
Das CSS Farbenmodul Level 4 definiert eine allgemeine Syntax, um den bei der Farbinterpolation zu verwendenden Farbmodell festlegen zu können. Eine solche Interpolationsangabe wird durch das Schlüsselwort in
eingeleitet, gefolgt von dem konkreten Farbkoordinatensystem, das verwendet werden soll. Bei den Systemen, die auf Polarkoordinaten basieren, kann zusätzlich die Richtung angegeben werden, um die der Farbwert gedreht werden soll.
Syntax
in <system> [ <richtung> hue ]
Bei in
und hue
handelt es sich um Schlüsselwörter. Als <system> ist eins der nachfolgend aufgelisteten Koordinatensysteme zu verwenden. Die möglichen Werte für <richtung> finden sich bei den Polarkoordinatensystemen.
Rechtwinklige Koordinatensysteme
Die Koordinaten in diesen Darstellungen haben in jeder Dimension zwei klar definierte, entgegengesetzte Enden.
- srgb
- Das ursprünglich verwendete Verfahren ist eine lineare Interpolation im sRGB-Farbraum. Diese Interpolation ist einfach realisierbar, aber der sRGB Farbraum ist nicht auf gleichförmige Ausleuchtung oder gleichmäßige Wahrnehmbarkeit ausgelegt, sondern auf einfache technische Darstellung auf einem Monitor. Deshalb sind sRGB-Farbverläufe oft zu dunkel oder zu sehr grau.
- srgb-linear
- xyz
- xyz-d50
- xyz-d65
- Diese Farbräume haben eine lineare Lichtintensität und führen zu einem Ergebnis, das der Mischung farbigen Lichts entspricht.
xyz
steht für den XYZ-Farbraum im CIE Normvalenzsystem, von dem die übrigen CIE-Farbräume wie Lab oder LCH abgeleitet sind.
- lab
- oklab
- L*a*b ist eine verständlichere Darstellung des CIE Normfarbraumes, basierend auf L (Helligkeit) und einer Positionierung auf den Komplementärfarbskalen grün/rot sowie blau/gelb. Der L*a*b Farbraum soll besser der menschlichen Wahrnehmung entsprechen, macht aber Schwierigkeiten bei der Bildverarbeitung, weshalb von Björn Ottoson eine verbesserte Umrechnung von XYZ in Lab vorgeschlagen wurde, die beim W3C Anklang fand. Dieses bessere Lab ist "okay", deshalb nannte man es oklab. In einer Farbinterpolation haben lab und oklab den Vorteil, dass der wahrgenommene Farbübergang gleichmäßiger ist.
Polare Koordinatensysteme
In einem polaren Koordinatensystem ist eine Achse kreisförmig, d.h. ihr Ende geht nahtlos wieder in den Anfang über
- hsl
- hwb
- Das System HSL (Hue - Saturation - Lightness = Farbton - Sättigung - Helligkeit) verwendet ein Farbenrad für den Farbton und leitet die übrigen Farben als Farbsättigung (0%=Grau, 100%=Vollton) und Helligkeit (von 0=Schwarz, 50%=Vollfarbe und 100%=Weiß) daraus ab. Das HWB System (Hue - Whiteness - Blackness) arbeitet ähnlich. Der Vorteil dieser Systeme ist, dass sie Menschen verständlicher sein sollen als RGB-Farbangaben. Bei einer Interpolation kann man Farbübergänge als Wechsel zwischen den Farbtönen darstellen. Das führt bei einem Übergang rot nach blau aber auch zu ganz anderen Farben, die eher ein Spektrum als einen Farbübergang bilden.
- lch
- oklch
- Der LCH Farbraum ist eine auf Polarkoordinaten umgerechnete Version des L*a*b-Farbraums und basiert auf Helligkeit (L=Luminanz), Farbsättigung (C=Chroma) und Farbton (H=Hue). Der Farbton ist dabei der, der auch im HSL-System genutzt wird. LCH gilt ebenfalls als gleichförmig in der Wahrnehmung, und soll bei Farbinterpolationen das „Ausgrauen“ der Farben vermeiden.
Interpolationsrichtung des Farbtons
In einem polaren Koordinatensystem stellt sich die Frage, in welcher Richtung man sich bei einer Interpolation des Farbtons um den Mittelpunkt des Farbrades drehen möchte. Der Übergang von H=100° zu H=200° kann aus der Folge 100, 101, 102, ... 199, 200 bestehen, aber auch aus der Folge 100, 99, ..., 1, 0, 359, 358, ... 201, 200.
Standardmäßig verwendet CSS den kleineren möglichen Drehwinkel. Das entspricht der Richtungsangabe shorter
in der Farbinterpolationsangabe. Den größeren Drehwinkel spezifiziert man mit der Angabe longer
.
Darüber hinaus gibt es noch die Angaben increasing
(aufsteigend) und decreasing
(absteigend), damit gibt man an, dass man in Richtung auf- oder absteigender Winkelwerte interpolieren möchte, ganz gleich, ob das der größere oder der kleinere Winkel ist.
Vergleichstafel
Die nachfolgende Vergleichstafel zeigt, wie sich die Interpolationsmethode auswirkt (in Arbeit!)
<style>
ul {
--from: hsl(340, 100%, 50%);
--to: hsl(130, 100%, 50%);
}
li {
height: 2em;
background: linear-gradient(to right var(--hue-scheme), var(--from), var(--to)) right center / 85% 100% no-repeat;
}
</style>
<ul>
<li style="--hue-scheme: in srgb">SRGB</li>
...
<li style="--hue-scheme: in oklch longer hue">OKLCH longer hue</li>
</ul>
Anhang: Hue-Rad
Weblinks
- ↑ CCSSWG: CSS Color Module Level 5
- ↑ CCSSWG: Relative Color Syntax (CSS Color Module Level 5)
- ↑ CSS-Syntax für relative Farben (developer.chrome.com)
- ↑ Farbe kontrastieren (developer.chrome.com)
- ↑ Simplify Your Color Palette With CSS Color-Mix() (smashing magazine)