Nachträglich angeflanschte Dark Modes hinterlassen eine erkennbare Spur: eine Variable hier, ein !important dort, eine duplizierte dark.css, die Sprint für Sprint vom hellen Design abweicht. Das Problem ist nicht die Farbe, sondern die fehlende Struktur. Design Tokens als CSS Custom Properties liefern diese Struktur — ohne Abhängigkeit und ohne JavaScript-Schicht.
Ein Token ist keine Farbe
Die häufigste Verwechslung besteht darin, einen Rohwert (#1e40af) mit einem Token gleichzusetzen. Ein Design Token ist eine benannte Absicht: „die Farbe des Haupttextes“, nicht „ein dunkles Blau“. Daraus folgt eine Organisation in zwei Schichten. Die primitive Schicht enthält die Rohwerte, die von Komponenten nie direkt verwendet werden. Die semantische Schicht enthält die Absichten und ist die einzige, die Selektoren anfassen.
:root {
/* Schicht 1: Primitive (nie direkt verwendet) */
--gray-900: #111418;
--gray-50: #f7f8fa;
--blue-500: #2563eb;
--blue-300: #93c5fd;
/* Schicht 2: Semantik (die API der Komponenten) */
--color-bg: var(--gray-50);
--color-text: var(--gray-900);
--color-accent: var(--blue-500);
}Der Wartungsvorteil zeigt sich sofort: Ein Wechsel des Markentons wird in den Primitiven erledigt, ein im Accessibility-Audit beanstandeter Kontrast in der semantischen Schicht. Die Komponenten bleiben unverändert — sie konsumieren var(--color-text).
Eine Komponente, die eine Rohfarbe referenziert, ist technische Schuld, die sich selbst nicht kennt. Eine Komponente, die ein semantisches Token referenziert, ist ein Vertrag.
Der Dark Mode als Neudefinition
Ist diese Trennung einmal etabliert, wird der Dark Mode zu einem unspektakulären Vorgang — genau das ist das Ziel. Nichts wird dupliziert: Nur die semantische Schicht wird neu definiert. Primitive bleiben, Komponenten bleiben, nur die Zuordnungstabelle ändert sich.
1. Die Systemeinstellung respektieren
Ausgangspunkt ist prefers-color-scheme, das die vom Nutzer auf Betriebssystemebene geäußerte Präferenz abbildet. Sie zu ignorieren heißt, eine ausdrückliche Einstellung zu übergehen.
@media (prefers-color-scheme: dark) {
:root {
--color-bg: var(--gray-900);
--color-text: var(--gray-50);
--color-accent: var(--blue-300);
}
}2. Eine ausdrückliche Wahl zulassen
Ein Attribut am Wurzelelement überschreibt die Systemeinstellung, wenn der Nutzer manuell umschaltet. Die Reihenfolge der Regeln bestimmt die Priorität: Die ausdrückliche Wahl muss in beide Richtungen gewinnen.
:root[data-theme='dark'] { /* dieselben Neudefinitionen */ }
@media (prefers-color-scheme: dark) {
:root:not([data-theme='light']) { /* dieselben Neudefinitionen */ }
}3. Das Aufblitzen beim Laden vermeiden
Die einzige tatsächlich nötige Zeile JavaScript ist ein blockierendes Skript im <head>, das das gespeicherte Design vor dem ersten Rendern anwendet. Jeder andere Ansatz erzeugt ein helles Aufblitzen auf Seiten, die im Dark Mode geladen werden.
<script>
try {
var t = localStorage.getItem('theme');
if (t) document.documentElement.setAttribute('data-theme', t);
} catch (e) {}
</script>color-scheme: light oder dark auf :root zu deklarieren ist kein Detail. Es weist den Browser an, Formularelemente, Scrollbalken und native Felder anzupassen. Ohne diese Deklaration verrät sich ein dunkles Design stets durch seine <select>-Elemente.Was die Methode verhindert
| Häufiges Symptom | Ursache | Antwort über Tokens |
|---|---|---|
Abweichende dark.css | Duplizierte Regeln | Ein Stylesheet, semantische Neudefinition |
Anhäufung von !important | Spezifitätskonflikte | Komponenten lesen nur eine Variable |
| Zu geringer Kontrast im Dark Mode | Farben von Fall zu Fall gewählt | Zentrale Korrektur an einem Token |
| Helles Aufblitzen beim Laden | Design nach dem Rendern angewendet | Blockierendes Skript im <head> |
Was bleibt
Ein wartbares helles/dunkles Design braucht weder Framework noch JavaScript-Schicht: zwei Token-Schichten, eine semantische Neudefinition und ein Dreizeiler gegen das anfängliche Aufblitzen. Der wesentliche Teil der Arbeit ist eine Architekturentscheidung, die vor der ersten Stilregel fällt.
Diese Methode wende ich seit mehreren Jahren in Kundenprojekten an; das Design dieser Website ist eine direkte Umsetzung. Die Regel, von der ich nicht mehr abweiche: Keine Komponente referenziert eine Primitive. An dem Tag, an dem diese Regel fällt, ist die Schuld binnen sechs Monaten zurück. — Simon Janvier
