Helle und dunkle Paletten: Kontrast prüfen und Grenzen erkennen

Management Summary
Kontrast bezeichnet den sichtbaren Unterschied zwischen einem Websiteelement und dessen Hintergrund. In hellen und dunklen Ansichten hilft ausreichender Kontrast, Texte, Bedienelemente und Markierungen zu erkennen. Eine vollständige Farbpalette allein belegt das nicht: Entscheidend sind das konkrete Farbpaar, Schriftgröße, Transparenz und Bedienzustand. Deshalb kann dieselbe Gestaltung in einer Ansicht gut lesbar und in der anderen schwierig sein. Farbrechnungen geben Hinweise; die dargestellte und bedienbare Seite entscheidet über den praktischen Nutzen.
Inhalt
Ein helles und ein dunkles Design können dieselben CSS-Variablennamen mit unterschiedlichen Farbwerten verwenden. Für lesbare Texte zählt jedoch das tatsächlich sichtbare Paar aus Vordergrund und Hintergrund. Eine Palette liefert mögliche Farben; erst die Verwendung auf der Seite zeigt, welche Kontraste geprüft werden müssen.

Welche Grenze gilt?
WCAG 2.2 verlangt auf Stufe AA für normalen Text grundsätzlich mindestens 4,5:1. Für großen Text reichen 3:1: Gemeint sind mindestens 18 Punkt beziehungsweise 24 CSS-Pixel oder 14 Punkt fett, entsprechend ungefähr 18,67 CSS-Pixel. Stufe AAA verlangt 7:1 für normalen und 4,5:1 für großen Text. Ausnahmen bestehen unter anderem für Logos, rein dekorativen Text und Text in inaktiven Bedienelementen.
Für visuelle Informationen, die zum Erkennen von Bedienelementen, Zuständen oder bedeutungstragenden Grafiken erforderlich sind, ist zusätzlich das Nicht-Text-Kriterium 1.4.11 relevant. Die Grenze beträgt 3:1 zu angrenzenden Farben, mit den dort genannten Ausnahmen. Nicht jeder einzelne Rand muss diese Grenze erfüllen, wenn das Element bereits durch andere ausreichend erkennbare Merkmale identifizierbar ist.
Eine geringe Zahl bedeutet deshalb nicht automatisch einen WCAG-Verstoß. Zuerst müssen Funktion, Größe, Zustand und tatsächlicher Hintergrund feststehen. Umgekehrt erklärt ein Variablenname wie --border-soft eine erforderliche Begrenzung nicht zur Dekoration.
Ein nachrechenbares Beispiel
Für den deckenden Textfarbwert #5e7184 auf #f1f5f9 ergibt die WCAG-Formel ungefähr 4,595593:1. Dieses konkrete Paar erreicht die AA-Grenze für normalen Text. Eine Anzeige mit zwei Nachkommastellen lautet 4,60:1; verglichen wird trotzdem der ungerundete Wert.
#777777 auf Weiß ergibt dagegen ungefähr 4,478089:1 und verfehlt 4,5:1. #767676 auf Weiß erreicht ungefähr 4,542225:1. Eine kleine Farbänderung kann also die Grenze überschreiten. Ein Zielwert von 4,6:1 bietet etwas Abstand, garantiert aber nicht, dass der Kontrast nach späteren Änderungen des Hintergrunds weiterhin ausreicht.
Das folgende Python-Beispiel akzeptiert ausschließlich deckende sechsstellige sRGB-Hexfarben. Die Grenzstelle für die Linearisierung beträgt 0,04045. Der ältere Wert 0,03928 führt bei ganzzahligen 8-Bit-Kanälen zu derselben Zweigwahl; das Beispiel verwendet die aktuelle Definition. Alpha, Verläufe, CSS-Kaskade und andere Farbräume liegen außerhalb des Programms.
"""WCAG 2.2 ratio for two opaque six-digit sRGB hex colours only."""
import re
def luminance(value):
if not isinstance(value, str) or not re.fullmatch(r"#?[0-9a-fA-F]{6}", value):
raise ValueError("Expected six-digit opaque sRGB hex colour")
value = value.removeprefix("#")
channels = [int(value[i:i+2], 16) / 255 for i in (0, 2, 4)]
linear = [c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4
for c in channels]
return sum(w * c for w, c in zip((0.2126, 0.7152, 0.0722), linear))
def contrast(foreground, background):
a, b = luminance(foreground), luminance(background)
return (max(a, b) + 0.05) / (min(a, b) + 0.05)
if __name__ == "__main__":
ratio = contrast("#5e7184", "#f1f5f9")
print(f"{ratio:.4f}:1; AA normal text: {ratio >= 4.5}")Vier Grenzen einer reinen Palettenprüfung
- Namen ersetzen keine Verwendung.
--on-accentdeutet auf Text auf einer Akzentfläche hin. Eine CSS-Regel kann den Wert trotzdem anders verwenden. Ebenso kann ein als „weich“ benannter Wert funktional wichtiger Text sein. - Fehlende Überschreibung bedeutet nicht automatisch Fallback. Ein dunkles Design kann Werte aus einer gemeinsamen Basis erben. Selektoren, Kaskade und Vererbung bestimmen den berechneten Wert. Ein
var()-Fallback greift unter bestimmten Bedingungen; eine fehlende zweite Deklaration allein beweist keinen Fehler. - Transparenz und Verläufe benötigen den tatsächlichen Untergrund. Der Alphawert bestimmt die Transparenz. Die sichtbare Farbe ergibt sich aus der teilweise durchsichtigen Farbe und den darunterliegenden Ebenen. Bei Bildern oder Verläufen zählt der ungünstigste relevante Bereich hinter dem Text. Dieser Bereich kann auch innerhalb eines Verlaufs liegen, nicht nur an dessen Enden.
- Zustände verändern die Paare. Fokus, Hover, ausgewählte Elemente, Fehlermeldungen und hervorgehobene Karten können andere Hintergründe verwenden. Ein korrektes Standardpaar ist keine Freigabe sämtlicher Zustände oder der ganzen Website.

Fokus und Formularbeschriftung
Ein Fokusindikator markiert das aktuell für Tastatureingaben ausgewählte Bedienelement, etwa durch einen sichtbaren Rahmen. Ein selbst gestalteter Fokusindikator muss die anwendbaren Anforderungen an erkennbare Zustände erfüllen. WCAG 2.4.13 auf Stufe AAA ergänzt Anforderungen an die Indikatorfläche und an mindestens 3:1 zwischen denselben Pixeln im fokussierten und unfokussierten Zustand. Dieser Vergleich ist von der Prüfung angrenzender Farben nach 1.4.11 zu unterscheiden. Unveränderte Browserdarstellung und weitere ausdrücklich genannte Fälle haben eigene Ausnahmen.
Platzhaltertext in einem aktiven Eingabefeld benötigt den anwendbaren Textkontrast. Ein gut lesbarer Platzhalter ersetzt dennoch keine passende Feldbeschriftung: Der Hinweis verschwindet bei der Eingabe. Zweck und Beispiel sollten auch während der Eingabe verständlich bleiben.
Was das Werkzeug leisten kann
Der verlinkte Palettenprüfer berechnet Farbpaare lokal im Browser. Die aktuelle Implementierung liest Deklarationen mit einem Textmuster und errät Rollen aus Namen. Die Prüfung löst keine echte CSS-Kaskade auf: Bei mehrfacher Deklaration gewinnt im Werkzeug der erste gefundene Wert, sogar Deklarationen in Kommentaren können eingelesen werden. Werte mit var() oder oklch() werden nicht aufgelöst.
Alphawerte werden gekennzeichnet, aber nicht in den Kontrast eingerechnet. Ein isolierter Test mit vollständig transparentem Schwarz auf Weiß liefert dadurch 21:1 und ein gutes Gesamturteil trotz Alphahinweis. Ein weiterer Test behandelt --text-soft als Dekoration und nimmt den Wert von den Befunden aus. Ein gutes Ergebnis ist daher nur ein Hinweis für die erkannten hypothetischen Paare, keine Abnahme der gerenderten Oberfläche.
Sechs isolierte Tests der Werkzeuglogik und zwölf Tests des Python-Beispiels sichern diese konkreten Aussagen ab. Die Rechnergebnisse ersetzen keine Sicht- und Zustandsprüfung im Browser. Für eine belastbare Prüfung gehören beide Themes, tatsächlich verwendete Farbpaare und die relevanten Bedienelementzustände zusammen.
Fragen und Antworten
Kann ein angezeigter Wert von 4,50 trotzdem durchfallen?
Ja. Ein Wert knapp unter 4,5 kann auf 4,50 gerundet erscheinen. Die Entscheidung muss vor der Rundung erfolgen.
Gilt ein sehr blasser Rand immer als Dekoration?
Nein. Maßgeblich ist die Funktion, nicht die Farbe oder der Variablenname. Eine für die Bedienung oder das Verständnis erforderliche Darstellung benötigt die jeweils anwendbare Prüfung.
Beweisen zwei vollständige Paletten Barrierefreiheit?
Nein. Palettenvollständigkeit und Kontrastberechnung decken nur einen Teil der Anforderungen ab. Die tatsächliche Darstellung, Zustände, Beschriftungen und weitere WCAG-Kriterien bleiben gesondert zu prüfen.


