Dark Mode für die Website umsetzen: CSS-Methoden im Überblick

Ein dunkles Farbschema gehört für viele Nutzerinnen und Nutzer inzwischen zum erwarteten Standard. Wer abends liest, empfindet helle Flächen schnell als grell, und auf OLED-Displays spart Dunkelheit zusätzlich etwas Energie. Die gute Nachricht: Einen brauchbaren Dark Mode bekommst du mit reinem CSS und ein paar Zeilen JavaScript hin. Dieser Ratgeber zeigt die wichtigsten Umsetzungswege, ihre Stärken und die Stolperfallen, die in der Praxis am häufigsten übersehen werden.

Automatische Erkennung mit prefers-color-scheme

Der einfachste Einstieg ist die Media Query prefers-color-scheme. Sie liest aus, ob das Betriebssystem oder der Browser auf eine helle oder dunkle Darstellung eingestellt ist. Du definierst dein normales, helles Design wie gewohnt und überschreibst innerhalb der Media Query nur die Farben, die im dunklen Modus anders sein sollen.

@media (prefers-color-scheme: dark) {
  body {
    background: #14161a;
    color: #e6e6e6;
  }
}

Der große Vorteil: Es ist kein JavaScript nötig, und die Seite respektiert sofort die Systempräferenz. Der Nachteil ist genauso klar – die Besucher können das Schema nicht selbst umschalten, wenn ihre Wahl von der Systemeinstellung abweicht. Für reine Inhaltsseiten ohne hohen Interaktionsanspruch reicht dieser Ansatz oft trotzdem völlig aus.

CSS Custom Properties als Farb-Token

Sobald deine Seite mehr als eine Handvoll Farben hat, wird das Überschreiben einzelner Regeln unübersichtlich. Die saubere Lösung sind CSS Custom Properties, also Variablen, die du als zentrale Farb-Token definierst. Du legst alle Farben einmal auf dem Wurzelelement fest und verwendest im restlichen Stylesheet ausschließlich diese Variablen.

:root {
  --bg: #ffffff;
  --text: #1a1a1a;
  --accent: #2563eb;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14161a;
    --text: #e6e6e6;
    --accent: #6ea8fe;
  }
}
body { background: var(--bg); color: var(--text); }

Der Charme dieser Methode: Du musst nur die Variablen an einer Stelle ändern, der Rest des Layouts zieht automatisch nach. Das gilt für Buttons, Rahmen, Karten und alles andere. Diese Token-Struktur ist außerdem die Basis für den manuellen Umschalter, weil du dieselben Variablen einfach über ein Attribut neu belegen kannst.

Manueller Toggle mit data-Attribut und localStorage

Viele Nutzer möchten selbst entscheiden, unabhängig vom System. Dafür ergänzt du einen Umschalter, der ein Attribut am html-Element setzt – etwa data-theme="dark". Im CSS definierst du die dunklen Token dann nicht nur in der Media Query, sondern zusätzlich für dieses Attribut.

html[data-theme="dark"] {
  --bg: #14161a;
  --text: #e6e6e6;
}

Mit etwas JavaScript merkst du dir die Wahl in localStorage und stellst sie beim nächsten Besuch wieder her:

const saved = localStorage.getItem('theme');
if (saved) document.documentElement.dataset.theme = saved;

function toggleTheme() {
  const next = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
  document.documentElement.dataset.theme = next;
  localStorage.setItem('theme', next);
}

Ein wichtiges Detail: Lies den gespeicherten Wert so früh wie möglich aus, idealerweise in einem kleinen Inline-Skript im <head>. Sonst erscheint beim Laden kurz das helle Design, bevor JavaScript umschaltet – dieses Aufblitzen wird oft als FOUC (Flash of Unstyled Content) bezeichnet und wirkt unsauber.

Kontrast und WCAG auch im dunklen Modus einhalten

Dunkel heißt nicht automatisch augenfreundlich. Reines Schwarz mit reinem Weiß erzeugt einen sehr harten Kontrast, der bei längerem Lesen anstrengt und ein Nachflackern (Halation) verursachen kann. Bewährt hat sich ein sehr dunkles Grau als Hintergrund und ein leicht gedämpftes Hellgrau als Textfarbe statt reinem Weiß.

Die WCAG-Vorgaben gelten unverändert: Für normalen Fließtext solltest du ein Kontrastverhältnis von mindestens 4,5:1 erreichen, für große Schrift genügt etwa 3:1. Prüfe deine dunklen Token genauso konsequent wie die hellen – gerade Akzent- und Linkfarben verlieren auf dunklem Grund schnell an Kontrast und müssen aufgehellt werden.

Bilder, Schatten und Logos anpassen

Farben sind nur die halbe Miete. Auf dunklem Grund verlieren weiche Schlagschatten ihre Wirkung, weil ein dunkler Schatten auf dunklem Hintergrund kaum sichtbar ist. Setze im Dark Mode eher auf feine Rahmen oder leicht hellere Flächen, um Tiefe anzudeuten, statt auf Schatten.

Bilder und Logos brauchen ebenfalls Aufmerksamkeit. Ein Logo mit dunkler Schrift auf transparentem Grund verschwindet im Dunkeln. Hier helfen mehrere Strategien:

  1. Eine zweite, helle Logo-Variante per <picture> oder CSS einblenden.
  2. Grelle Fotos mit filter: brightness(.85) leicht abdunkeln.
  3. Reinen Bildern einen dezenten hellen Hintergrund geben, wenn Transparenz stört.

Denke auch an SVG-Icons, die per currentColor gefärbt sind – diese passen sich automatisch an, wenn du die Textfarbe als Token führst. Das ist ein weiterer Grund, konsequent mit Variablen zu arbeiten.

Welche Methode passt zu welchem Projekt?

Die Wahl hängt vom Anspruch deines Projekts ab. Die folgende Übersicht stellt die drei gängigen Umsetzungswege mit Aufwand sowie Vor- und Nachteilen gegenüber.

Methode Aufwand Vorteile Nachteile
Nur System (prefers-color-scheme) Gering Kein JavaScript, respektiert Systemwahl, schnell umgesetzt Keine manuelle Umschaltung möglich
Nur Toggle (data-Attribut) Mittel Volle Kontrolle für Nutzer, Wahl wird gespeichert Ignoriert Systemeinstellung beim ersten Besuch, JavaScript nötig
Kombiniert (System + Toggle) Höher Beste Nutzererfahrung, Standard folgt System, Override möglich Mehr Logik, FOUC vermeiden erfordert Inline-Skript

In der Praxis ist die kombinierte Variante der empfohlene Weg: Standardmäßig folgt die Seite der Systempräferenz, und der Umschalter überschreibt sie nur, wenn der Besucher das ausdrücklich will. Diese Logik bildest du ab, indem dein gespeicherter Wert Vorrang vor der Media Query erhält.

Typische Fehler vermeiden

Drei Stolperfallen tauchen immer wieder auf. Erstens das erwähnte Aufblitzen des hellen Themes – vermeide es mit einem frühen Inline-Skript. Zweitens vergessene Bereiche wie eingebettete Formulare, Tabellen oder Code-Blöcke, die plötzlich grell wirken, weil sie eigene Hintergrundfarben hatten. Drittens harte Übergänge: Ein kurzer transition auf Hintergrund- und Textfarbe lässt das Umschalten weicher wirken, sollte aber nicht zu lang sein, sonst fühlt es sich träge an.

Wenn du systematisch mit Token arbeitest, deinen Kontrast prüfst und das Speichern der Nutzerwahl sauber löst, hast du einen Dark Mode, der robust ist und sich pflegen lässt. Weitere praktische Helfer rund um Farben, Kontrast und Code findest du in unseren Webtools, und ergänzende Beiträge gibt es im News-Bereich.

Häufige Fragen

Brauche ich für Dark Mode zwingend JavaScript?

Nein. Mit prefers-color-scheme funktioniert ein dunkles Schema komplett ohne JavaScript. Du brauchst es erst, wenn Nutzer das Theme manuell umschalten und die Wahl gespeichert werden soll.

Wie verhindere ich das kurze Aufblitzen des hellen Designs?

Lies den gespeicherten Theme-Wert in einem kleinen Inline-Skript ganz oben im <head> aus und setze das Attribut, bevor der Body gerendert wird. So steht das richtige Schema schon beim ersten Frame fest.

Warum sollte ich kein reines Schwarz und Weiß verwenden?

Der extreme Kontrast strengt beim Lesen an und kann ein Nachflackern um Buchstaben erzeugen. Ein sehr dunkles Grau und ein gedämpftes Hellgrau sind angenehmer und wirken hochwertiger.

Gelten Barrierefreiheits-Regeln im Dark Mode genauso?

Ja, die WCAG-Kontrastvorgaben gelten unverändert. Fließtext braucht weiterhin mindestens 4,5:1, große Schrift etwa 3:1. Prüfe die dunklen Farb-Token mit einem Kontrastwerkzeug.

Wie merke ich mir die Nutzerwahl über Seitenwechsel hinweg?

Speichere die Auswahl in localStorage und lies sie beim Laden jeder Seite wieder aus. Der gespeicherte Wert sollte Vorrang vor der Systemeinstellung haben.

Was passiert mit Bildern und Logos im dunklen Modus?

Helle Logos oder grelle Fotos brauchen Anpassung: eine alternative Logo-Variante, eine leichte Abdunklung per Filter oder ein dezenter Hintergrund. SVGs mit currentColor passen sich automatisch an.