Dark Mode implementieren: Ein vollständiger Entwicklerleitfaden
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://colorfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://colorfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://colorfyi.com/entity//)
Use the native HTML custom element.
Dark Mode hat sich von einer Nischenpräferenz zu einem erwarteten Feature entwickelt. Nutzer auf allen Plattformen – macOS, Windows, Android, iOS – können eine systemweite dunkle Darstellung einstellen und erwarten, dass Websites und Apps diese respektieren. Dark Mode korrekt zu implementieren erfordert mehr als das Tauschen von Weiß gegen Schwarz: Es erfordert einen systematischen Ansatz bei Farbe, Kontrast und Benutzersteuerung. Dieser Leitfaden führt durch den gesamten Prozess – von der CSS-Architektur über JavaScript-Toggle-Mechaniken bis hin zum gründlichen Testen beider Themes.
CSS Custom Properties für Themes
Der wartbarste Weg, Dark Mode in CSS zu handhaben, sind Custom Properties (auch CSS-Variablen genannt). Statt Farbwerte in Ihren Stylesheets zu verstreuen, definieren Sie jede Farbe als Variable auf :root und überschreiben diese Variablen für Dark Mode. Komponentenstile referenzieren ausschließlich die Variablen – niemals rohe Hex-Codes.
Ihre hellen und dunklen Paletten definieren
Beginnen Sie mit einer Light-Mode-Palette als Standard. Ein sauberer Ausgangspunkt könnte so aussehen:
:root {
/* Hintergründe */
--color-bg-base: #FFFFFF;
--color-bg-elevated: #F8F9FA;
--color-bg-overlay: #F1F3F5;
/* Text */
--color-text-primary: #1A1A2E;
--color-text-secondary: #4A4A6A;
--color-text-muted: #6C757D;
/* Rahmen */
--color-border: #DEE2E6;
--color-border-strong: #ADB5BD;
/* Marke / Akzent */
--color-accent: #3B82F6;
--color-accent-hover: #2563EB;
/* Feedback */
--color-success: #22C55E;
--color-warning: #F59E0B;
--color-danger: #EF4444;
}
Definieren Sie anschließend Überschreibungen für Dark Mode in einem separaten Block. Die entscheidende Erkenntnis: Sie invertieren keine Farben, sondern wählen eine andere, speziell für dunkle Oberflächen konzipierte Palette:
[data-theme="dark"] {
/* Hintergründe */
--color-bg-base: #0F0F17;
--color-bg-elevated: #1A1A2E;
--color-bg-overlay: #252540;
/* Text */
--color-text-primary: #E8E8F0;
--color-text-secondary: #A8A8C0;
--color-text-muted: #6A6A88;
/* Rahmen */
--color-border: #2E2E4A;
--color-border-strong: #4A4A6A;
/* Marke / Akzent — oft etwas heller für Lesbarkeit auf dunklem Hintergrund */
--color-accent: #60A5FA;
--color-accent-hover: #93C5FD;
/* Feedback — leicht entsättigt, um Härte zu vermeiden */
--color-success: #4ADE80;
--color-warning: #FCD34D;
--color-danger: #F87171;
}
Beachten Sie, dass der Akzent #3B82F6 im Light Mode zu #60A5FA im Dark Mode wird. Der Farbton ist gleich, aber die Helligkeit nimmt zu – dies ist notwendig, weil sich der Kontrastkontext umgekehrt hat. Eine Farbe, die WCAG AA auf weißem Hintergrund besteht, wird auf nahezu schwarzem Hintergrund fast immer scheitern, es sei denn, Sie passen sie an. Der Schattengenerator lässt Sie den vollständigen 50–950-Bereich jeder Farbe erkunden und so den passenden Ton für jedes Theme auszuwählen.
Variablen in Komponenten verwenden
Mit der definierten Palette referenziert jede Komponente Variablen statt roher Werte:
.card {
background-color: var(--color-bg-elevated);
border: 1px solid var(--color-border);
color: var(--color-text-primary);
}
.btn-primary {
background-color: var(--color-accent);
color: #FFFFFF;
}
.btn-primary:hover {
background-color: var(--color-accent-hover);
}
Wenn das [data-theme="dark"]-Attribut am <html>-Element vorhanden ist, werden alle Variablen gleichzeitig aktualisiert und jede Komponente, die auf sie verweist, ändert ihr Aussehen – ohne zusätzliches CSS.
Der prefers-color-scheme Media Query
Bevor ein Benutzer überhaupt mit einem Umschalter interagiert, können Sie seine Betriebssystempräferenz über den prefers-color-scheme Media Query respektieren. Dieser Media Query löst aus, wenn das Betriebssystem auf dunkles Erscheinungsbild eingestellt ist.
@media (prefers-color-scheme: dark) {
:root {
--color-bg-base: #0F0F17;
--color-bg-elevated: #1A1A2E;
--color-bg-overlay: #252540;
--color-text-primary: #E8E8F0;
--color-text-secondary: #A8A8C0;
--color-text-muted: #6A6A88;
--color-border: #2E2E4A;
--color-border-strong: #4A4A6A;
--color-accent: #60A5FA;
--color-accent-hover: #93C5FD;
--color-success: #4ADE80;
--color-warning: #FCD34D;
--color-danger: #F87171;
}
}
Dieser Ansatz funktioniert ohne JavaScript, verursacht keinen Layout-Shift und respektiert die erklärte Präferenz des Nutzers unmittelbar beim Laden der Seite. Er ist die richtige Grundlage. Die Einschränkung: Nutzer können sie in Ihrer App nicht überschreiben – ist das Betriebssystem dunkel, ist die Website dunkel, ohne Ausweg. Deshalb schichten die meisten Produktionsimplementierungen einen JavaScript-Toggle oben auf den Media Query.
Beide Ansätze kombinieren
Das empfohlene Muster verwendet den Media Query als Standard und das data-theme-Attribut als explizite Überschreibung. Dies lässt sich mit einem CSS-Spezifizitätstrick oder durch korrekte Reihenfolge der Regeln handhaben:
/* 1. Light-Mode-Standard */
:root {
--color-bg-base: #FFFFFF;
/* ... */
}
/* 2. OS-Dark-Mode-Überschreibung (wenn keine explizite Präferenz gesetzt) */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--color-bg-base: #0F0F17;
/* ... */
}
}
/* 3. Expliziter Dark Mode (Nutzer über JS umgeschaltet) */
[data-theme="dark"] {
--color-bg-base: #0F0F17;
/* ... */
}
Der Selektor :not([data-theme="light"]) im Media Query bewirkt, dass die OS-Dark-Präferenz nur greift, wenn der Nutzer sich nicht explizit für den Light Mode entschieden hat. Sobald er umschaltet, gewinnt seine explizite Wahl.
Toggle-Mechanismus mit JavaScript
Ein gut implementierter Toggle tut drei Dinge: Er ändert das aktuelle Erscheinungsbild sofort, speichert die Präferenz in localStorage und liest die gespeicherte Präferenz beim Seitenload vor dem ersten Paint.
Präferenz beim Laden lesen
Dieses Skript muss im <head> laufen – bevor die Seite rendert – um einen Flash des falschen Themes zu verhindern:
<head>
<script>
(function() {
const stored = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const theme = stored ?? (prefersDark ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', theme);
})();
</script>
</head>
Dadurch wird data-theme auf <html> gesetzt, bevor Styles angewendet werden. Der Browser berechnet die korrekten Custom-Property-Werte ab dem ersten Paint – kein Flash.
Die Toggle-Funktion
function toggleTheme() {
const current = document.documentElement.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
}
// An eine Schaltfläche binden
document.getElementById('theme-toggle').addEventListener('click', toggleTheme);
Toggle-Schaltflächenzustand synchronisieren
Die Toggle-Schaltfläche sollte visuell den aktuellen Modus widerspiegeln. Ein einfacher Ansatz verwendet Icons:
<button id="theme-toggle" aria-label="Toggle dark mode">
<span class="icon-light">☀️</span>
<span class="icon-dark">🌙</span>
</button>
[data-theme="dark"] .icon-light { display: none; }
[data-theme="dark"] .icon-dark { display: inline; }
[data-theme="light"] .icon-light { display: inline; }
[data-theme="light"] .icon-dark { display: none; }
Da die Icon-Sichtbarkeit durch CSS-Variablen gesteuert wird, die an data-theme gebunden sind, aktualisiert sich der Schaltflächenzustand automatisch, wenn sich das Attribut ändert – kein zusätzliches JavaScript erforderlich.
Farbadaptionsstrategien
Die Auswahl von Dark-Mode-Farben ist nicht so einfach wie das Invertieren der hellen Palette. Mehrere Prinzipien leiten gute dunkle Farbentscheidungen.
Kontrast reduzieren, nicht nur umkehren
Reiner weißer Text auf reinem schwarzem Hintergrund (#FFFFFF auf #000000) ist technisch maximaler Kontrast – 21:1 –, ist aber kognitiv ermüdend für längeres Lesen. Reduzieren Sie beide Extreme: Verwenden Sie ein Off-White wie #E8E8F0 für Fließtext und ein sehr dunkles Marineblau wie #0F0F17 für den Seitenhintergrund. Das bewahrt ausreichend Kontrast (noch über 15:1) und reduziert gleichzeitig visuelle Ermüdung.
Verwenden Sie den Kontrastprüfer, um zu überprüfen, dass jede Text-/Hintergrundkombination in Ihrem dunklen Theme mindestens WCAG AA erfüllt (4,5:1 für normalen Text, 3:1 für großen Text). Häufige Schwachstellen sind:
- Platzhaltertext in Formularfeldern
- Labels deaktivierter Schaltflächen
- Sekundäre Metadatentexte (Zeitstempel, Autorangaben)
- Nur-Icon-Schaltflächen ohne sichtbare Labels
Layered Elevation mit dunklen Oberflächen
Im Light Mode wird Elevation typischerweise durch Schlagschatten ausgedrückt. Im Dark Mode werden Schatten auf dunklen Hintergründen unsichtbar. Die Material Design 3-Spezifikation führte einen effektiveren Ansatz ein: Hellere Oberflächen wirken erhöhter. Verwenden Sie subtil hellere Hintergründe für erhöhte Komponenten:
/* Dark-Mode-Elevationsskala */
--color-bg-base: #0F0F17; /* Seitenhintergrund */
--color-bg-elevated: #1A1A2E; /* Karten, Seitenleisten */
--color-bg-overlay: #252540; /* Modals, Dropdowns */
--color-bg-tooltip: #2E2E4A; /* Tooltips */
#0F0F17 als Basis, #1A1A2E für Karten, #252540 für Modals – jeder Schritt ist etwa 8–10% heller in HSL-Helligkeitstermen. Das erzeugt eine klare visuelle Hierarchie ohne Schatten.
Dark-Mode-Farben leicht entsättigen
Stark gesättigte Farben wirken auf dunklen Hintergründen hart und neonartig. Beim Anpassen von Markenfarben für Dark Mode sollten Sie die Sättigung um 10–20% reduzieren und gleichzeitig die Helligkeit erhöhen. Statt einem lebhaften #22C55E Erfolgsgrün bevorzugen Sie #4ADE80 – heller und leicht weniger gesättigt, das als Erfolg gelesen wird ohne Augenbelastung.
Der Schattengenerator ist hierfür ideal: Geben Sie das primäre Grün oder Blau Ihrer Marke ein und erkunden Sie den 300–400-Bereich für Dark-Mode-Text und Icon-Verwendung, gegenüber dem 500–600-Bereich für interaktive Elemente.
Bilder und Medien
Bilder mit weißem Hintergrund wirken im Dark Mode störend. CSS kann helfen:
/* Härte von Bildern im Dark Mode reduzieren */
[data-theme="dark"] img:not([src*=".svg"]) {
filter: brightness(0.9) contrast(1.05);
}
/* Oder Bilder leicht mit dem Hintergrund verschmelzen lassen */
[data-theme="dark"] img {
mix-blend-mode: luminosity;
opacity: 0.9;
}
Für SVG-Icons, die sich anpassen müssen, bedeutet die Verwendung von currentColor als Fill-Wert, dass sie automatisch die aktuelle Textfarbe übernehmen:
.icon { color: var(--color-text-secondary); }
<svg fill="currentColor" viewBox="0 0 24 24">...</svg>
Beide Modi testen
Gründliches Testen verhindert, dass Dark-Mode-Regressionen in die Produktion gelangen.
Browser-DevTools-Emulation
Chrome und Firefox bieten Dark-Mode-Emulation in den DevTools an, ohne die OS-Einstellung zu ändern. In Chrome: DevTools öffnen, auf das Dreipunktmenü klicken, zu Weitere Tools → Rendering gehen und „CSS-Medienmerkmal prefers-color-scheme emulieren" auf „dark" setzen. Das ermöglicht den direkten Vergleich beider Modi.
Automatisiertes Kontrasttesting
Manuelles Spot-Checking ist fehleranfällig. Integrieren Sie automatisiertes Kontrastaudit in Ihren Entwicklungsworkflow. Verwenden Sie Tools wie Axe oder Lighthouse in CI, um neue Farbzusätze zu erkennen, die WCAG-Schwellenwerte nicht erfüllen. Der Kontrastprüfer lässt Sie schnell ein Vordergrund-/Hintergrundpaar gegen alle WCAG-Ebenen prüfen – fügen Sie ein beliebiges Hex-Paar ein und sehen Sie das Verhältnis sofort.
Mit echtem Inhalt testen
Dark-Mode-Bugs treten oft auf Seiten mit dynamischen Inhalten auf: nutzerhochgeladene Bilder, Drittanbieter-Einbettungen, Diagramme und Karten. Testen Sie mit einem realistischen Inhaltsbeispiel, nicht nur mit der Komponentenbibliothek Ihres Designsystems isoliert.
OS-Level-Testing
Überprüfen Sie nach der Verifizierung über DevTools-Emulation mit dem tatsächlich auf Dark Mode eingestellten Betriebssystem. Der prefers-color-scheme Media Query löst basierend auf der OS-Einstellung aus, und einige Browser verhalten sich leicht unterschiedlich, je nachdem ob die Einstellung real oder emuliert ist. Testen Sie auch den Übergang: Wechseln Sie Modi, während eine Seite geöffnet ist, und bestätigen Sie, dass keine Layout-Shifts oder Rendering-Artefakte auftreten.
Checkliste häufiger Fallstricke
- Fest kodierte Hex-Werte in Komponenten-CSS statt Variablen – durchsuchen Sie Ihre Stylesheets nach rohen Hex-Codes und ersetzen Sie sie durch Variablen
- SVG-Icons mit fest kodiertem
fill="#000000"– zufill="currentColor"ändern - Drittanbieter-Komponenten, die
data-themenicht respektieren – in eine bereichsspezifische CSS-Schicht einwickeln color-scheme-Eigenschaft nicht gesetzt –color-scheme: light darkzu:roothinzufügen, damit auch Browser-Chrome (Scrollbalken, Formularelemente) sich anpasst<meta name="color-scheme">fehlt im<head>– hinzufügen, damit der Browser die richtige Hintergrundfarbe anwenden kann, bevor CSS geladen wird
<meta name="color-scheme" content="light dark">
:root {
color-scheme: light dark;
}
Diese kleine Ergänzung lässt native Scrollbalken, Datumsauswahl und andere OS-gerenderte Formularelemente automatisch zu ihren dunklen Varianten wechseln – ein Detail, das viele Implementierungen übersehen.
Wichtige Erkenntnisse
- Definieren Sie alle Farben als CSS Custom Properties auf
:rootund überschreiben Sie sie für Dark Mode mit[data-theme="dark"]. Komponentenstile referenzieren nur Variablen, sodass das Theme-Wechseln null Aufwand bedeutet, sobald die Palette etabliert ist. - Verwenden Sie
prefers-color-scheme: darkals automatischen Standard für Nutzer, die ihr Betriebssystem auf dunkles Erscheinungsbild eingestellt haben. Schichten Sie oben einen JavaScript-Toggle mitlocalStorage-Persistenz für Nutzer, die überschreiben möchten. - Führen Sie das Anti-Flash-Skript im
<head>vor dem CSS-Laden aus, um den First-Paint-Flash des falschen Themes zu verhindern. - Dark-Mode-Farben sind keine invertierten Light-Mode-Farben – reduzieren Sie extremen Kontrast, verwenden Sie hellere Hintergründe für Elevation und entsättigen Sie Markenakzente leicht, um neonhafte Härte zu vermeiden.
- Überprüfen Sie jedes Text-/Hintergrundpaar mit dem Kontrastprüfer und verwenden Sie den Schattengenerator, um den richtigen Ton jeder Markenfarbe für beide Themes zu finden.
- Fügen Sie
color-scheme: light darkund das entsprechende<meta>-Tag hinzu, damit native Browser-UI-Elemente (Scrollbalken, Eingabefelder) ebenfalls automatisch wechseln.