HEX, RGB, HSL und die neueren Farbräume

Wie HEX, RGB, HSL, LCH und OKLCH zusammenhängen, warum eine HSL-Palette in den Mitteltönen matschig wird und was Gamut-Clipping und Alpha-Compositing mit der Farbe machen, die am Ende herauskommt.

Eine Farbe in CSS besteht aus drei oder vier Zahlen plus einer Regel, wie sie zu lesen sind: dem Farbraum. Paletten, die auf dem Bildschirm ungleichmäßig wirken, sind meist in einem Raum abgestuft, der nicht dazu passt, wie das Sehen funktioniert.

HEX und RGB sind dieselben Zahlen

#3B82F6 sind drei Bytes zur Basis 16: 3B ist 59, 82 ist 130, F6 ist 246, rgb(59, 130, 246) ist also dieselbe Farbe zur Basis 10, und ein Farbkonverter wechselt verlustfrei zwischen beiden.

Die dreistellige Kurzform verdoppelt jede Ziffer, statt sie aufzufüllen, #F80 wird also zu #FF8800 und nicht zu #F08000; nur 4.096 Farben haben eine Kurzform. #RGBA fügt auf dieselbe Weise eine Alpha-Ziffer hinzu, und #RRGGBBAA schreibt alle vier Bytes aus, wobei dieses Alpha-Byte von 0 bis 255 läuft (1A sind 10 %, 80 sind 50 %, CC sind 80 %), während jedes andere Alpha in CSS von 0 bis 1 läuft. Die moderne Syntax nimmt außerdem durch Leerzeichen getrennte Komponenten mit dem Alpha hinter einem Schrägstrich: rgb(59 130 246 / 50%).

Diese Zahlen sind keine Lichtmengen. sRGB codiert jeden Kanal über eine Übertragungskurve von etwa 2,2, 128 gibt also rund 21,6 % des Lichts ab, das 255 abgibt, und nicht die Hälfte, und jede Mischung, die auf den rohen Werten gerechnet wird, erbt diese Kurve.

HSL, HSV und die Helligkeit, die keine ist

HSL ordnet denselben RGB-Würfel zu einem Zylinder um: Der Farbton ist ein Winkel (0 Rot, 120 Grün, 240 Blau), die Sättigung ist der Abstand von der grauen Mittelachse, und die Helligkeit läuft von 0 über 50 %, den reinen Farbton, bis 100 %, Weiß. HSV tauscht die Helligkeit gegen den Wert, dessen oberes Ende der reine Farbton statt Weiß ist; Aufhellungen entstehen dort durch Absenken der Sättigung. Keines von beiden weiß irgendetwas über Wahrnehmung.

FarbeHSLRelative LeuchtdichteOKLCH-Helligkeit
#FFFF00hsl(60 100% 50%)0,9280,97
#0000FFhsl(240 100% 50%)0,0720,45

Beide behaupten 50 % Helligkeit; die eine gibt etwa dreizehnmal so viel Licht ab wie die andere. Eine Token-Reihe, in der jeder Farbton auf 50% festgenagelt ist, liest sich als Durcheinander von Gewichten.

Die HSL-Helligkeit bei festem Farbton und fester Sättigung abzustufen scheitert aus demselben Grund und aus einem weiteren: Die Sättigung wird gegen den Spielraum gemessen, der bei dieser Helligkeit zur Verfügung steht, die Stufe bei 50 % ist also die farbigste, und alles beiderseits davon verwässert. Der Farbtonwinkel bleibt zudem stehen, während das wahrgenommene Chroma zusammenbricht, und genau das lässt die mittleren Stufen matschig wirken. Sie sind nicht die abgedunkelte Grundfarbe, sie sind die Grundfarbe, um einen Betrag vergraut, den niemand gewählt hat.

Am schlimmsten zeigt sich das bei Gelb. Die HSL-Helligkeit zu senken führt ein Gelb geradewegs ins Olive, denn ein dunkles Gelb bei diesem Farbtonwinkel ist schlicht Olive, und es gelb zu halten heißt, den Farbton auf dem Weg nach unten Richtung Orange zu drehen. Blau hat das umgekehrte Problem und liegt so tief in der Leuchtdichte, dass seine nutzbare Variation vollständig oberhalb von 50 % liegt.

LCH und OKLCH

LCH ist die Polarform von CIE Lab, entstanden aus Farbabgleichsexperimenten: Helligkeit 0 bis 100, Chroma (Buntheit, ohne festes Maximum) und ein Farbtonwinkel. OKLCH hat dieselbe Form über Oklab, das die Farbtonverschiebungen korrigiert, für die Lab bekannt ist, am sichtbarsten Blautöne, die beim Aufhellen ins Violette abdriften.

.a { color: oklch(0.62 0.21 260); }        /* L 0 to 1, C about 0 to 0.37, H in degrees */
.b { color: oklch(62% 0.21 260 / 50%); }   /* percentages and alpha both allowed */
.c { color: lch(52% 82 285); }             /* L runs 0 to 100 here */

Wahrnehmungsgleichheit bedeutet, dass gleicher numerischer Abstand nahe an gleichem wahrgenommenem Abstand liegt. Eine Rampe in Schritten von 0,08 Helligkeit sieht nach gleichmäßigen Schritten aus, eine Reihe von Farbtönen, die auf eine Helligkeit festgelegt sind, liest sich als eine Reihe, und die Helligkeit zu ändern lässt den Farbton dort, wo du ihn hingesetzt hast. Auch die Interpolation kann den Raum nutzen, etwa in linear-gradient(in oklch, #0000FF, #FFFF00). Eine Warnung: Die OKLCH-Helligkeit liegt der scheinbaren Helligkeit viel näher als HSL, aber sie ist nicht die WCAG-Leuchtdichteformel, Textpaare gehen also weiterhin durch einen Kontrastprüfer.

Gamut und Clipping

Ein Gamut ist die Menge der Farben, die ein Raum darstellen kann. sRGB ist der seit Langem gültige Standard; Display P3 deckt etwa ein Viertel mehr des sichtbaren Farbbereichs ab, und fast der gesamte Zugewinn liegt in tiefen Rot- und Grüntönen. Das Chroma in OKLCH ist nach oben offen, eine Farbe hinzuschreiben, die kein Bildschirm zeigen kann, ist also leicht.

@supports (color: color(display-p3 1 1 1)) {
  .vivid { background: color(display-p3 0.9 0.1 0.14); }
}

Clipping pro Kanal holt eine Farbe außerhalb des Gamuts zurück, indem es jeden Kanal unabhängig an seiner Grenze festhält; das verschiebt den Farbton und drückt benachbarte Abstufungen auf einen Wert zusammen, sodass Verläufe Streifen bilden und Details verschwinden. CSS Color 4 bildet stattdessen ab: Helligkeit und Farbton halten und das Chroma in OKLCH so weit senken, bis die Farbe hineinpasst.

Deshalb kann ein Screenshot eines kräftigen Fotos flau aussehen. Das Foto trägt ein P3-Profil, und das Display zeigt es vollständig; ein nach sRGB umgewandelter Export presst diese gesättigten Pixel in ein kleineres Volumen, und Rot- und Grüntöne haben den weitesten Weg.

Alpha-Compositing

Eine halbtransparente Farbe über einem Hintergrund erzeugt eine dritte, deckende Farbe, Kanal für Kanal:

result = alpha * source + (1 - alpha) * backdrop

Schwarz bei 50 % über Weiß ergibt (127.5, 127.5, 127.5), also #808080. Aus diesem Zufall stammt die Vorstellung, „Schwarz mit 50 % Deckkraft ist Grau“, und sie stimmt auf Weiß und sonst nirgends: Dasselbe Schwarz über #3B82F6 ergibt etwa #1E417B, ein dunkles Blau, und über einem Foto ergibt es in jedem Pixel eine andere Farbe. Halbtransparentes Schwarz ist ein Abdunkelungsoperator, kein Grau.

Das Compositing rechnet auf den codierten Werten, dieses #808080 hat also eine relative Leuchtdichte von etwa 0,216 statt 0,5. Miss den zusammengesetzten Hexwert, niemals die deklarierte Farbe. Auch Alpha stapelt sich nicht wie erwartet: Zwei Ebenen mit je 50 % decken 75 % ab, denn die zweite wirkt nur auf das, was die erste durchgelassen hat.

Aufhellungen, Abdunklungen, Trübungen und Harmonien

BegriffTraditionelles RezeptIn OKLCH
AufhellungGrundfarbe plus WeißL anheben, C leicht senken
AbdunklungGrundfarbe plus SchwarzL senken
TrübungGrundfarbe plus GrauC bei festem L senken

Harmonien sind Farbtonversätze. Sie wählen einen Akzent; sie bauen kein System.

HarmonieVersätzeGut für
Komplementär+180°einen Akzent gegen einen dominanten Farbton, auch wenn es flimmert, sobald beide gesättigt sind
Analog±30°ruhige Gruppierungen, Hintergründe, Zustände innerhalb einer Familie
Triadisch+120°, +240°kategoriale Sätze wie Diagrammserien

Versätze auf dem RGB-Kreis sind wahrnehmungsmäßig nicht gleichmäßig, denn dieser Kreis verwendet einen unverhältnismäßig großen Bogen auf Grün; behandle eine berechnete Harmonie also als ersten Entwurf und korrigiere nach Augenmaß. Ein Palettengenerator, der Aufhellungen, Abdunklungen und Harmonien aus einer Grundfarbe erzeugt, bringt diesen Entwurf schnell auf den Bildschirm.

Die Neutralrampe braucht eine eigene Entscheidung. Ein reines Grau, bei dem Rot, Grün und Blau gleich sind, wirkt neben einem farbigen Interface tot und leicht schmutzig. Gib den Neutraltönen ein kleines Chroma, etwa 0,005 bis 0,02 in OKLCH, nahe am Markenfarbton: warme Grautöne um 60° bis 90° lesen sich wie Papier, kühle Grautöne um 250° wirken technisch. Lass dieses Chroma zu den hellsten Stufen hin auslaufen, damit Hintergründe nicht getönt aussehen.

Farbenfehlsichtigkeit

Etwa 1 von 12 Männern und 1 von 200 Frauen hat eine Farbsinnstörung. Rot-Grün-Typen machen fast alles davon aus, mit weitem Abstand die Deuteranomalie; Blau-Gelb-Typen vom Tritan-Typ betreffen weniger als 1 von 10.000.

Die Verwechslungen, die in Interfaces zählen, sind Rot gegen Grün bei ähnlicher Helligkeit, Grün gegen Braun und Orange, Violett gegen Blau und Rosa gegen Grau. Das Protan-Sehen dunkelt Rottöne zusätzlich ab, ein Rot, das für Dringlichkeit gewählt wurde, kann also das leiseste Element auf dem Bildschirm werden.

Farbe darf deshalb nie der einzige Bedeutungsträger sein. Verbinde jeden Zustand mit einer Beschriftung, einem Icon, einer Form oder einer Position, und lass gepaarte Zustände sich nicht nur im Farbton, sondern auch in der Helligkeit unterscheiden, denn ein Rot und ein Grün mit gleicher OKLCH-Helligkeit sind die denkbar schlechteste Kombination. Einen Screenshot in Graustufen umzuwandeln findet solche Kollisionen in Sekunden.