WCAG-konforme Farben systematisch prüfen
Eine schöne Farbpalette ist noch keine lesbare Farbpalette. Ein Farbkontrast-Audit deckt auf, welche Text-Hintergrund-Kombinationen einer Tailwind CSS Palette WCAG AA tatsächlich erfüllen, bevor sie im Design System zur Falle für Nutzer mit eingeschränktem Sehvermögen werden.
Inhaltsverzeichnis
- 1. Warum Farbkontrast über Lesbarkeit entscheidet
- 2. WCAG Kontrast Anforderungen: AA, AAA und Großtext
- 3. Das Kontrast Problem in Tailwinds Standardpalette
- 4. Kontrastverhältnisse berechnen: die Formel dahinter
- 5. Tailwind Farbstufen systematisch auditieren
- 6. Automatisierung mit Skripten und CI Pipelines
- 7. Custom Paletten in Tailwind v4 kontrastsicher gestalten
- 8. Dark Mode Kontrast: doppelte Prüfung nötig
- 9. Farbkontrast Werkzeuge im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum Farbkontrast über Lesbarkeit entscheidet
Ein Farbkontrast-Audit beginnt mit einer unbequemen Wahrheit: Die meisten Design Teams wählen Farben nach ästhetischem Empfinden, nicht nach messbarem Kontrastverhältnis. Ein helles Grau auf Weiß wirkt am Bildschirm des Designers angenehm zurückhaltend, für Nutzer mit Sehschwäche, unter direktem Sonnenlicht oder auf einem schlecht kalibrierten Display kann derselbe Text jedoch praktisch unlesbar werden. Genau hier setzt ein systematisches Farbkontrast-Audit an: Es ersetzt subjektives Empfinden durch eine berechenbare Kennzahl.
Tailwind CSS liefert mit seiner Standardpalette bereits eine große Bandbreite an Farbstufen von 50 bis 950, doch nicht jede Kombination aus Textfarbe und Hintergrundfarbe innerhalb dieser Palette erfüllt automatisch ausreichenden Kontrast. Ein Farbkontrast-Audit prüft systematisch, welche Kombinationen tatsächlich funktionieren, und macht damit sichtbar, wo ein Design System stillschweigend Barrieren für Millionen Nutzer mit Sehbeeinträchtigungen aufbaut.
2. WCAG Kontrast Anforderungen: AA, AAA und Großtext
Die Web Content Accessibility Guidelines definieren in Erfolgskriterium 1.4.3 ein Mindestkontrastverhältnis von 4.5 zu 1 für normalen Fließtext auf Konformitätsstufe AA. Für Großtext, definiert als mindestens 18 Punkt oder 14 Punkt fett, reicht ein reduziertes Verhältnis von 3 zu 1, weil größere Zeichen auch bei geringerem Kontrast noch erkennbar bleiben. Stufe AAA verschärft diese Werte auf 7 zu 1 für normalen Text und 4.5 zu 1 für Großtext, ein Niveau, das viele kommerzielle Produkte anstreben, aber selten vollständig erreichen.
Ein Farbkontrast-Audit muss diese unterschiedlichen Schwellenwerte je nach Textgröße und Schriftgewicht getrennt betrachten. Eine Kombination, die für eine Überschrift in 24 Punkt ausreicht, kann für denselben Farbton in einem 14 Punkt Fließtext bereits unzureichend sein. Wer ein Audit nur mit einem einzigen pauschalen Schwellenwert durchführt, übersieht regelmäßig Fälle, in denen kleine Schrift mit ansonsten akzeptabler Farbe trotzdem WCAG verletzt.
3. Das Kontrast Problem in Tailwinds Standardpalette
Tailwinds Standardpalette ist bewusst breit gefächert, mit elf Abstufungen pro Farbfamilie von 50 bis 950. Das bedeutet aber auch, dass benachbarte Stufen wie slate-400 und slate-500 auf weißem Hintergrund völlig unterschiedliche Kontrastwerte liefern, obwohl sie sich visuell nur geringfügig unterscheiden. Ein häufiger Fehler in Projekten ist die Verwendung von text-slate-400 für sekundären Text auf weißem Hintergrund, eine Kombination, die mit einem Kontrastverhältnis von etwa 2.9 zu 1 klar unter der WCAG AA Grenze von 4.5 zu 1 liegt.
Ein Farbkontrast-Audit der Standardpalette zeigt, dass erst ab slate-500 beziehungsweise bei den meisten Farbfamilien ab der 600er oder 700er Stufe auf weißem Hintergrund verlässlich WCAG AA erreicht wird. Diese Erkenntnis lässt sich in ein Design System Regelwerk überführen: Sekundärer Text sollte nie unterhalb einer bestimmten Farbstufe liegen, unabhängig davon, wie gut es optisch im Mockup aussieht.
/* Common contrast trap: slate-400 on white fails WCAG AA for normal text */
.secondary-text-wrong {
color: #94a3b8; /* slate-400, contrast ratio ~2.9:1 on white */
}
/* slate-600 reliably reaches WCAG AA (4.5:1) for normal-sized body text */
.secondary-text-correct {
color: #475569; /* slate-600, contrast ratio ~7.2:1 on white */
}
/* slate-500 only clears the reduced 3:1 threshold for large/bold text */
.large-text-only {
color: #64748b; /* slate-500, contrast ratio ~4.6:1 on white, borderline */
font-size: 1.5rem;
font-weight: 700;
}
4. Kontrastverhältnisse berechnen: die Formel dahinter
Ein Kontrastverhältnis basiert auf der relativen Luminanz beider Farben, nicht auf einem einfachen Helligkeitsvergleich der RGB Werte. Die relative Luminanz gewichtet Rot, Grün und Blau unterschiedlich, weil das menschliche Auge Grün am empfindlichsten wahrnimmt und Blau am wenigsten. Aus den beiden relativen Luminanzwerten berechnet sich das Kontrastverhältnis als Verhältnis der hellen zur dunklen Luminanz, jeweils zuzüglich eines kleinen Ausgleichswerts von 0.05, um eine Division durch null zu vermeiden.
Für ein Farbkontrast-Audit muss diese Formel nicht von Hand nachgerechnet werden, es genügt, sie einmal als Funktion zu implementieren und dann programmatisch über die gesamte Tailwind Palette laufen zu lassen. Genau das ermöglicht ein systematisches, wiederholbares Audit, statt einzelne Farbkombinationen manuell in einem Online Tool zu prüfen.
// Contrast ratio calculation following the WCAG 2.x formula
function relativeLuminance(hex) {
const rgb = hexToRgb(hex).map((channel) => {
const c = channel / 255;
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
});
return 0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2];
}
function contrastRatio(hexA, hexB) {
const lumA = relativeLuminance(hexA);
const lumB = relativeLuminance(hexB);
const lighter = Math.max(lumA, lumB);
const darker = Math.min(lumA, lumB);
return (lighter + 0.05) / (darker + 0.05);
}
function hexToRgb(hex) {
const clean = hex.replace('#', '');
return [0, 2, 4].map((i) => parseInt(clean.substring(i, i + 2), 16));
}
console.log(contrastRatio('#475569', '#ffffff').toFixed(2)); // 7.24 -> passes AA and AAA
console.log(contrastRatio('#94a3b8', '#ffffff').toFixed(2)); // 2.86 -> fails AA
5. Tailwind Farbstufen systematisch auditieren
Ein vollständiges Farbkontrast-Audit testet nicht nur eine einzelne Kombination, sondern jede relevante Textfarbe gegen jede relevante Hintergrundfarbe, die im Projekt tatsächlich vorkommt. Der praktikable Ansatz: die Tailwind Konfiguration als JavaScript Objekt importieren, alle Farbstufen extrahieren und in einer verschachtelten Schleife jede Kombination gegen den WCAG AA Schwellenwert prüfen. Das Ergebnis ist eine Matrix, die auf einen Blick zeigt, welche Kombinationen sicher, welche grenzwertig und welche klar unzulässig sind.
Besonders wertvoll wird ein solches Audit, wenn es nicht nur Weiß und Schwarz als Hintergrund testet, sondern auch die tatsächlich im Projekt verwendeten Hintergrundfarben wie slate-50 für Cards oder slate-900 für dunkle Sektionen. Ein Text, der auf reinem Weiß WCAG AA erfüllt, kann auf einem leicht getönten Kartenhintergrund bereits knapp darunter fallen, ein Detail, das reine Theorie ohne projektspezifisches Farbkontrast-Audit leicht übersieht.
// Audit every text/background combination actually used in the project
import resolveConfig from 'tailwindcss/resolveConfig';
import tailwindConfig from './tailwind.config.js';
const config = resolveConfig(tailwindConfig);
const usedTextColors = ['slate-400', 'slate-500', 'slate-600', 'slate-700'];
const usedBackgrounds = ['white', 'slate-50', 'slate-900'];
const results = [];
for (const textKey of usedTextColors) {
for (const bgKey of usedBackgrounds) {
const textHex = resolveColor(config, textKey);
const bgHex = resolveColor(config, bgKey);
const ratio = contrastRatio(textHex, bgHex);
results.push({
text: textKey,
background: bgKey,
ratio: ratio.toFixed(2),
passesAA: ratio >= 4.5,
});
}
}
console.table(results);
6. Automatisierung mit Skripten und CI Pipelines
Ein manuelles Farbkontrast-Audit ist wertvoll für die initiale Bestandsaufnahme, verliert aber schnell an Wirkung, wenn neue Komponenten regelmäßig neue Farbkombinationen einführen. Die nachhaltige Lösung ist die Integration des Audit Skripts in die CI Pipeline, sodass jeder Pull Request automatisch geprüft wird, bevor eine neue, kontrastschwache Kombination überhaupt in den Hauptzweig gelangt. Ein einfacher Exit Code ungleich null bei mindestens einer fehlgeschlagenen Kombination reicht aus, um den Build fehlschlagen zu lassen.
Ergänzend lässt sich ein solches Skript mit axe-core kombinieren, das im Browser Kontext tatsächlich gerenderte Elemente prüft, statt nur statische Farbwerte aus der Konfiguration zu vergleichen. Diese Kombination aus statischem Farbkontrast-Audit auf Konfigurationsebene und dynamischem Test auf gerenderten Seiten deckt sowohl systematische Design System Fehler als auch Einzelfälle ab, in denen eine Komponente entgegen der Konfiguration inline Styles mit problematischem Kontrast setzt.
#!/usr/bin/env bash
# CI step: fail the build if any color combination drops below WCAG AA
set -euo pipefail
echo "Running Tailwind contrast audit..."
node scripts/contrast-audit.js --config tailwind.config.js --threshold 4.5
if [ $? -ne 0 ]; then
echo "[ERROR] Contrast audit failed: at least one combination is below WCAG AA"
exit 1
fi
echo "[OK] All audited color combinations pass WCAG AA"
7. Custom Paletten in Tailwind v4 kontrastsicher gestalten
Wer in Tailwind CSS v4 eigene Markenfarben über die @theme Direktive definiert, verlässt die durchgetestete Standardpalette und trägt die volle Verantwortung für ausreichenden Kontrast selbst. Der empfohlene Workflow: Für jede neue Markenfarbe sofort eine passende dunkle Textvariante und eine passende helle Hintergrundvariante berechnen, statt Kontrast erst nachträglich im fertigen Interface zu bemerken. Ein Farbkontrast-Audit direkt beim Anlegen neuer Token verhindert, dass problematische Farben überhaupt erst in Komponenten verbaut werden.
Praktisch bedeutet das, für jede Markenfarbe mindestens zwei kontrastgeprüfte Textvarianten zu definieren, eine für helle und eine für dunkle Hintergründe, und diese als eigene Design Tokens zu benennen statt als rohe Hex Werte in Komponenten zu verstreuen. So bleibt das Farbkontrast-Audit ein einmaliger Aufwand pro Token, nicht ein wiederkehrender Aufwand pro Komponente.
/* Tailwind v4: brand color tokens with pre-audited contrast-safe text variants */
@import "tailwindcss";
@theme {
--color-brand: oklch(0.55 0.18 250); /* base brand color */
--color-brand-text-on-light: oklch(0.32 0.15 250); /* audited: 7.1:1 on white */
--color-brand-text-on-dark: oklch(0.85 0.08 250); /* audited: 8.4:1 on slate-900 */
}
.brand-heading-light-bg {
color: var(--color-brand-text-on-light);
}
.brand-heading-dark-bg {
color: var(--color-brand-text-on-dark);
}
8. Dark Mode Kontrast: doppelte Prüfung nötig
Ein häufiger Denkfehler bei Dark Mode Implementierungen: Wenn eine Farbkombination im hellen Modus WCAG AA erfüllt, wird oft angenommen, dass die invertierte Kombination im dunklen Modus automatisch ebenfalls passt. Das stimmt fast nie, weil Kontrastverhältnisse nicht linear invertieren und weil viele Design Systeme im Dark Mode nicht einfach Farben vertauschen, sondern eigene, gedämpftere Farbtöne verwenden, um grelle, ermüdende Kontraste auf dunklem Hintergrund zu vermeiden.
Ein vollständiges Farbkontrast-Audit muss deshalb beide Modi getrennt durchlaufen, mit eigenen Text- und Hintergrundpaaren für Light und Dark Mode. Tailwinds dark: Modifier macht das technisch einfach umsetzbar, ersetzt aber nicht die inhaltliche Prüfung, ob dark:text-slate-300 auf dark:bg-slate-900 tatsächlich denselben Kontrastanspruch erfüllt wie das helle Pendant. Wer nur den hellen Modus auditiert, lässt in der Praxis oft die Hälfte der Nutzer außen vor, insbesondere weil Dark Mode inzwischen von einem erheblichen Anteil der Nutzer aktiv gewählt wird.
9. Farbkontrast Werkzeuge im Vergleich
Für ein Farbkontrast-Audit stehen unterschiedliche Werkzeuge zur Verfügung, die sich in Automatisierbarkeit, Genauigkeit und Integration in bestehende Tailwind Workflows unterscheiden.
| Werkzeug | Automatisierbar | Tailwind Integration | Typischer Einsatz |
|---|---|---|---|
| WebAIM Contrast Checker | Nein, manuell | Keine, Hex Werte einzeln eingeben | Stichprobenprüfung einzelner Farben |
| Eigenes Node Skript | Ja, vollständig | Liest tailwind.config.js direkt | Vollständiges Palette Audit, CI Integration |
| axe-core | Ja, im Browser Kontext | Testet gerenderte Elemente, nicht Konfiguration | End to end Tests auf echten Seiten |
| Figma Kontrast Plugins | Teilweise | Nur im Design Tool, nicht im Code | Frühe Prüfung vor der Implementierung |
| Lighthouse | Ja, in CI integrierbar | Testet gerenderte Seite als Ganzes | Grobe Übersicht, keine Palette Details |
In der Praxis ergänzen sich diese Werkzeuge am besten in Kombination: ein eigenes Node Skript für das vollständige, wiederholbare Farbkontrast-Audit der Konfiguration, axe-core für stichprobenartige End to end Tests auf echten Seiten, und ein Figma Plugin als frühe Warnung, bevor eine problematische Farbe überhaupt in den Code gelangt.
Mironsoft
Tailwind CSS, Barrierefreiheit und WCAG-konforme Frontend-Entwicklung
Farben, die auf jedem Bildschirm lesbar bleiben?
Wir führen ein vollständiges Farbkontrast-Audit eurer Tailwind Palette durch, für Light und Dark Mode, und integrieren ein automatisiertes Prüfskript in eure CI-Pipeline, damit kontrastschwache Farben gar nicht erst in Produktion landen.
Paletten-Audit
Systematische Prüfung aller Text-Hintergrund-Kombinationen
CI-Integration
Automatisiertes Kontrast-Skript, das den Build bei Verstößen stoppt
Dark Mode Prüfung
Getrennte Kontrastvalidierung für Light und Dark Mode Tokens
10. Zusammenfassung
Ein systematisches Farbkontrast-Audit ersetzt subjektives Design Empfinden durch eine messbare, wiederholbare Prüfung nach WCAG Standard. Die Formel hinter dem Kontrastverhältnis basiert auf relativer Luminanz, nicht auf einfacher Helligkeit, und lässt sich einmal implementieren, um dann programmatisch über die gesamte Tailwind Palette zu laufen. Tailwinds Standardpalette bietet zwar viele Farbstufen, doch nicht jede davon erreicht auf jedem Hintergrund ausreichenden Kontrast.
Wer ein Farbkontrast-Audit in die CI Pipeline integriert, verhindert dauerhaft, dass neue Komponenten unbemerkt kontrastschwache Farbkombinationen einführen. Besonders wichtig bleibt die getrennte Prüfung von Light und Dark Mode, da Kontrastverhältnisse sich zwischen den beiden Modi nicht automatisch übertragen. Custom Paletten in Tailwind CSS v4 sollten von Anfang an mit kontrastgeprüften Text Token entworfen werden, statt Kontrast erst nachträglich im fertigen Interface zu entdecken.
Farbkontrast-Audit für Tailwind-Paletten - das Wichtigste auf einen Blick
WCAG AA Mindestwert
4.5 zu 1 für normalen Text, 3 zu 1 für Großtext ab 18 Punkt oder 14 Punkt fett.
Kontraste programmatisch prüfen
Formel einmal implementieren, dann über die gesamte tailwind.config.js Palette laufen lassen.
Light und Dark Mode getrennt prüfen
Kontrastverhältnisse übertragen sich nicht automatisch zwischen den beiden Modi.
In CI Pipeline integrieren
Audit Skript im Build laufen lassen, damit kontrastschwache Farben nie in Produktion landen.