Der Dark Mode hat in letzter Zeit stark an Bedeutung gewonnen. Apple hat beispielsweise den Dark Mode in seine Betriebssysteme iOS und MacOS integriert. Windows und Google haben dasselbe getan.

Befassen wir uns mit dem Dark Mode im Kontext von Websites. Wir werden verschiedene Optionen und Ansätze zur Implementierung eines Dark-Mode-Designs sowie die damit verbundenen technischen Überlegungen vertiefen. Zudem werden wir zwischendurch einige Design-Tipps ansprechen.
Themes umschalten
Das typische Szenario ist, dass Sie bereits ein helles Theme für Ihre Website haben und nun ein dunkles Gegenstück erstellen möchten. Oder, selbst wenn Sie bei Null anfangen, werden Sie beide Themes haben: hell und dunkel. Ein Theme sollte als Standard definiert sein, den Benutzer beim ersten Besuch sehen – in den meisten Fällen das helle Theme (obwohl wir den Browser des Benutzers diese Wahl für uns treffen lassen können, wie wir noch sehen werden). Es sollte auch eine Möglichkeit geben, zum anderen Theme zu wechseln (was ebenfalls automatisch geschehen kann) – zum Beispiel, indem der Benutzer auf eine Schaltfläche klickt und sich das Farbschema ändert.
Es gibt verschiedene Ansätze, um dies umzusetzen
Verwendung einer Body-Klasse
Der Trick hierbei ist der Austausch einer Klasse, die als Ankerpunkt dient, um den Stil an jeder Stelle der Seite zu ändern.
<body class="dark-theme || light-theme">
Hier ist zum Beispiel ein Skript für eine Schaltfläche, die diese Klasse umschaltet
// Select the button
const btn = document.querySelector('.btn-toggle');
// Listen for a click on the button
btn.addEventListener('click', function() {
// Then toggle (add/remove) the .dark-theme class to the body
document.body.classList.toggle('dark-theme');
})
So können wir diese Idee nutzen
<body>
<button class="btn-toggle">Toggle Dark Mode</button>
<h1>Hey there! This is just a title</h1>
<p>I am just a boring text, existing here solely for the purpose of this demo</p>
<p>And I am just another one like the one above me, because two is better than having only one</p>
<a href="#">I am a link, don't click me!</a>
</body>
Die allgemeine Idee dieses Ansatzes ist es, die Dinge wie gewohnt zu stylen, dies als unseren „Standard“-Modus zu bezeichnen und dann einen vollständigen Satz an Farbstilen unter Verwendung einer Klasse am <body>-Element zu erstellen, die wir als „Dark“-Modus nutzen.
Nehmen wir an, unser Standard ist ein helles Farbschema. All diese „hellen“ Stile werden genau so geschrieben, wie Sie normalerweise CSS schreiben. Wenden wir auf Basis unseres HTML ein globales Styling auf den Body und auf Links an.
body {
color: #222;
background: #fff;
}
a {
color: #0033cc;
}
Gut. Wir haben dunklen Text (#222) und dunkle Links (#0033cc) auf einem hellen Hintergrund (#fff). Unser „Standard“-Theme hat einen soliden Start hingelegt.
Nun definieren wir diese Eigenschaftswerte neu, diesmal für eine andere Body-Klasse
body {
color: #222;
background: #fff;
}
a {
color: #0033cc;
}
/* Dark Mode styles */
body.dark-theme {
color: #eee;
background: #121212;
}
body.dark-theme a {
color: #809fff;
}
Die Stile für das dunkle Theme sind Nachfahren derselben Elternklasse – in diesem Beispiel .dark-theme –, die wir auf den <body>-Tag angewendet haben.
Wie „wechseln“ wir die Body-Klassen, um auf die dunklen Stile zuzugreifen? Wir können JavaScript verwenden! Wir wählen die Schaltflächen-Klasse (.btn-toggle) aus, fügen einen Listener für den Klick hinzu und hängen dann die Dark-Theme-Klasse (.dark-theme) an die Klassenliste des Body-Elements an. Dank Kaskade und Spezifität werden dadurch effektiv alle gesetzten „hellen“ Farben überschrieben.
Hier ist der vollständige Code in Aktion. Klicken Sie auf die Umschalttaste, um den Dark Mode ein- und auszuschalten.
Verwendung separater Stylesheets
Anstatt alle Stile in einem Stylesheet zusammenzufassen, könnten wir zwischen Stylesheets für jedes Theme umschalten. Dies setzt voraus, dass Sie vollständige Stylesheets bereitliegen haben.
Zum Beispiel ein Standard-Hell-Theme wie light-theme.css
/* light-theme.css */
body {
color: #222;
background: #fff;
}
a {
color: #0033cc;
}
Dann erstellen wir Stile für das dunkle Theme und speichern sie in einem separaten Stylesheet namens dark-theme.css.
/* dark-theme.css */
body {
color: #eee;
background: #121212;
}
body a {
color: #809fff;
}
Dies gibt uns zwei separate Stylesheets – eines für jedes Theme –, die wir im HTML-Bereich <head> verknüpfen können. Verknüpfen wir zuerst die hellen Stile, da wir diese als Standard bezeichnen.
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Light theme stylesheet -->
<link href="light-theme.css" rel="stylesheet" id="theme-link">
</head>
<!-- etc. -->
</html>
Wir verwenden eine ID #theme-link, die wir mit JavaScript auswählen können, um erneut zwischen hellem und dunklem Modus zu wechseln. Nur dass wir dieses Mal Dateien anstatt Klassen umschalten.
// Select the button
const btn = document.querySelector(".btn-toggle");
// Select the stylesheet <link>
const theme = document.querySelector("#theme-link");
// Listen for a click on the button
btn.addEventListener("click", function() {
// If the current URL contains "ligh-theme.css"
if (theme.getAttribute("href") == "light-theme.css") {
// ... then switch it to "dark-theme.css"
theme.href = "dark-theme.css";
// Otherwise...
} else {
// ... switch it to "light-theme.css"
theme.href = "light-theme.css";
}
});
Verwendung von Custom Properties (CSS-Variablen)
Wir können auch die Leistungsfähigkeit von CSS Custom Properties nutzen, um ein dunkles Theme zu erstellen! Dies hilft uns, separate Regelsätze für jedes Theme zu vermeiden, wodurch das Schreiben von Stilen viel schneller und Änderungen an einem Theme viel einfacher werden.
Wir können uns immer noch dafür entscheiden, eine Body-Klasse zu tauschen und diese Klasse zu verwenden, um die Custom Properties neu zu setzen.
// Select the button
const btn = document.querySelector(".btn-toggle");
// Listen for a click on the button
btn.addEventListener("click", function() {
// Then toggle (add/remove) the .dark-theme class to the body
document.body.classList.toggle("dark-theme");
});
Zuerst definieren wir die Standardwerte für helle Farben als Custom Properties im Body-Element
body {
--text-color: #222;
--bkg-color: #fff;
--anchor-color: #0033cc;
}
Nun können wir diese Werte für eine Body-Klasse .dark-theme neu definieren, genau wie wir es in der ersten Methode getan haben
body.dark-theme {
--text-color: #eee;
--bkg-color: #121212;
--anchor-color: #809fff;
}
Hier sind unsere Regelsätze für die Body- und Link-Elemente unter Verwendung von Custom Properties
body {
color: var(--text-color);
background: var(--bkg-color);
}
a {
color: var(--anchor-color);
}
Wir hätten unsere Custom Properties ebenso gut im Dokument-:root definieren können. Das ist völlig legitim und sogar gängige Praxis. In diesem Fall kämen alle Definitionen des Standard-Themes in :root { } und alle Dark-Theme-Eigenschaften in :root.dark-mode { }.
Verwendung von serverseitigen Skripten
Wenn wir bereits mit einer serverseitigen Sprache arbeiten, zum Beispiel PHP, dann können wir diese anstelle von JavaScript verwenden. Dies ist ein großartiger Ansatz, wenn Sie es vorziehen, direkt im Markup zu arbeiten.
<?php
$themeClass = '';
if (isset($_GET['theme']) && $_GET['theme'] == 'dark') {
$themeClass = 'dark-theme';
}
$themeToggle = ($themeClass == 'dark-theme') ? 'light' : 'dark';
?>
<!DOCTYPE html>
<html lang="en">
<!-- etc. -->
<body class="<?php echo $themeClass; ?>">
<a href="?theme=<?php echo $themeToggle; ?>">Toggle Dark Mode</a>
<!-- etc. -->
</body>
</html>
Wir können den Benutzer eine GET- oder POST-Anfrage senden lassen. Dann lassen wir unseren Code (in diesem Fall PHP) die entsprechende Body-Klasse anwenden, wenn die Seite neu geladen wird. Für diese Demonstration verwende ich eine GET-Anfrage (URL-Parameter).
Und ja, wir können Stylesheets genauso austauschen, wie wir es in der zweiten Methode getan haben.
<?php
$themeStyleSheet = 'light-theme.css';
if (isset($_GET['theme']) && $_GET['theme'] == 'dark') {
$themeStyleSheet = 'dark-theme.css';
}
$themeToggle = ($themeStyleSheet == 'dark-theme.css') ? 'light' : 'dark';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- etc. -->
<link href="<?php echo $themeStyleSheet; ?>" rel="stylesheet">
</head>
<body>
<a href="?theme=<?php echo $themeToggle; ?>">Toggle Dark Mode</a>
<!-- etc. -->
</body>
</html>
Diese Methode hat einen offensichtlichen Nachteil: Die Seite muss aktualisiert werden, damit die Umschaltung erfolgt. Aber eine serverseitige Lösung wie diese ist nützlich, um die Theme-Wahl des Benutzers über Seitenaktualisierungen hinweg beizubehalten, wie wir später sehen werden.
Welche Methode sollten Sie wählen?
Die „richtige“ Methode hängt von den Anforderungen Ihres Projekts ab. Bei einem großen Projekt könnten Sie beispielsweise auf CSS-Variablen setzen, um eine umfangreiche Codebasis besser zu verwalten. Wenn Ihr Projekt hingegen ältere Browser unterstützen muss, ist ein anderer Ansatz erforderlich.
Zudem spricht nichts dagegen, mehrere Methoden zu kombinieren. Manchmal ist eine Kombination von Ansätzen der effektivste Weg. Es mag sogar noch andere mögliche Methoden geben, als die hier besprochenen.
Dark Mode auf Betriebssystemebene
Bisher haben wir eine Schaltfläche zum Umschalten zwischen hellem und dunklem Modus verwendet, aber wir können diese Arbeit auch einfach dem Betriebssystem des Benutzers überlassen. Beispielsweise erlauben es viele Betriebssysteme den Benutzern, direkt in den Systemeinstellungen zwischen hellen und dunklen Themes zu wählen.

Reines CSS
Details
Glücklicherweise verfügt CSS über eine Media Query namens prefers-color-scheme, mit der die Farbschema-Präferenzen des Benutzers erkannt werden können. Sie kann drei mögliche Werte haben: keine Präferenz, hell und dunkel. Lesen Sie mehr darüber auf MDN.
@media (prefers-color-scheme: dark) {
/* Dark theme styles go here */
}
@media (prefers-color-scheme: light) {
/* Light theme styles go here */
}
Um sie zu nutzen, können wir die Stile für das dunkle Theme in die Media Query einfügen.
@media (prefers-color-scheme: dark) {
body {
color: #eee;
background: #121212;
}
a {
color: #809fff;
}
}
Wenn ein Benutzer nun den Dark Mode in den Systemeinstellungen aktiviert hat, erhält er standardmäßig die Dark-Mode-Stile. Wir müssen nicht auf JavaScript oder serverseitige Skripte zurückgreifen, um zu entscheiden, welcher Modus verwendet werden soll. Wir brauchen nicht einmal mehr die Schaltfläche!
JavaScript
Details
Wir können JavaScript nutzen, um das bevorzugte Farbschema des Benutzers zu erkennen. Dies ähnelt stark der ersten Methode, nur dass wir matchMedia() verwenden, um die Präferenz des Benutzers abzufragen.
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');nnif (prefersDarkScheme.matches) {n document.body.classList.add('dark-theme');n} else {n document.body.classList.remove('dark-theme');n}
Die Verwendung von JavaScript hat einen Nachteil: Da JavaScript erst nach dem CSS ausgeführt wird, kann es zu einem kurzen Aufblitzen des hellen Themes kommen. Das könnte als Fehler missverstanden werden.
Natürlich können wir stattdessen auch Stylesheets tauschen, wie in der zweiten Methode. Diesmal verknüpfen wir beide Stylesheets und nutzen die Media Query, um zu bestimmen, welches angewendet wird.
OS-Einstellungen überschreiben
Wir haben uns gerade angesehen, wie man die systemweiten Farbschema-Präferenzen eines Benutzers berücksichtigt. Aber was ist, wenn Benutzer ihre Systemeinstellung für eine bestimmte Seite überschreiben wollen? Nur weil ein Benutzer den Dark Mode für sein Betriebssystem bevorzugt, heißt das nicht unbedingt, dass er ihn auch auf einer Website möchte. Daher ist es eine gute Idee, eine Möglichkeit zu bieten, den Dark Mode manuell zu überschreiben, ungeachtet der Systemeinstellungen.
Code ansehen
Nutzen wir den Ansatz mit CSS-Variablen, um zu zeigen, wie das geht. Die Idee ist, die Variablen für beide Themes wie zuvor zu definieren, die Dark-Styles in die prefers-color-scheme Media Query zu packen und darin eine .light-theme-Klasse zu definieren, mit der wir die Dark-Mode-Eigenschaften überschreiben können, falls der Benutzer zwischen den beiden Modi wechseln möchte.
/* Default colors */
body {
--text-color: #222;
--bkg-color: #fff;
}
/* Dark theme colors */
body.dark-theme {
--text-color: #eee;
--bkg-color: #121212;
}
/* Styles for users who prefer dark mode at the OS level */
@media (prefers-color-scheme: dark) {
/* defaults to dark theme */
body {
--text-color: #eee;
--bkg-color: #121212;
}
/* Override dark mode with light mode styles if the user decides to swap */
body.light-theme {
--text-color: #222;
--bkg-color: #fff;
}
}
Nun können wir wieder auf unsere bewährte Schaltfläche zurückgreifen, um zwischen hellen und dunklen Themes umschalten zu können. Auf diese Weise respektieren wir standardmäßig die Farbschema-Präferenz des Betriebssystems und ermöglichen dem Benutzer, manuell zu wechseln.
// Listen for a click on the button
btn.addEventListener("click", function() {
// If the OS is set to dark mode...
if (prefersDarkScheme.matches) {
// ...then apply the .light-theme class to override those styles
document.body.classList.toggle("light-theme");
// Otherwise...
} else {
// ...apply the .dark-theme class to override the default light styles
document.body.classList.toggle("dark-theme");
}
});
Browser-Unterstützung
Die Media Query prefers-color-scheme wird von den wichtigsten Browsern unterstützt, darunter Chrome 76+, Firefox 67+, Chrome Android 76+, Safari 12.5+ (13+ auf iOS) und Samsung Internet Browser. Der IE wird nicht unterstützt.
Das ist eine vielversprechende Unterstützung! Can I Use schätzt die Benutzerabdeckung auf 80,85 %.
Zu den Betriebssystemen, die derzeit den Dark Mode unterstützen, gehören MacOS (Mojave oder neuer), iOS (13.0+), Windows (10+) und Android (10+).
Speichern der Benutzereinstellungen
Was wir uns bisher angesehen haben, tut genau das, was es verspricht: den Theme-Wechsel basierend auf einer OS-Präferenz oder einem Klick. Das ist toll, bleibt aber nicht erhalten, wenn der Benutzer eine andere Seite der Website besucht oder die aktuelle Seite neu lädt.
Wir müssen die Wahl des Benutzers speichern, damit sie auf der gesamten Website und bei künftigen Besuchen konsistent angewendet wird. Dazu können wir die Wahl des Benutzers beim Umschalten im localStorage speichern. Cookies sind für diese Aufgabe ebenfalls gut geeignet.
Sehen wir uns beide Ansätze an.
Verwendung von localStorage
Wir haben ein Skript, das das ausgewählte Theme beim Umschalten im localStorage speichert. Wenn die Seite neu geladen wird, ruft das Skript die Wahl aus dem localStorage ab und wendet sie an. Da JavaScript oft erst nach dem CSS ausgeführt wird, ist dieser Ansatz anfällig für ein „kurzes Aufblitzen des falschen Themes“ (Flash of Incorrect Theme, FOIT).
Code ansehen
// Select the button
const btn = document.querySelector(".btn-toggle");
// Select the theme preference from localStorage
const currentTheme = localStorage.getItem("theme");
// If the current theme in localStorage is "dark"...
if (currentTheme == "dark") {
// ...then use the .dark-theme class
document.body.classList.add("dark-theme");
}
// Listen for a click on the button
btn.addEventListener("click", function() {
// Toggle the .dark-theme class on each click
document.body.classList.toggle("dark-theme");
// Let's say the theme is equal to light
let theme = "light";
// If the body contains the .dark-theme class...
if (document.body.classList.contains("dark-theme")) {
// ...then let's make the theme dark
theme = "dark";
}
// Then save the choice in localStorage
localStorage.setItem("theme", theme);
});
Verwendung von Cookies mit PHP
Um das Flashen zu vermeiden, können wir ein serverseitiges Skript wie PHP verwenden. Anstatt die Theme-Präferenz des Benutzers im localStorage zu speichern, erstellen wir ein Cookie via JavaScript. Aber auch das ist nur dann sinnvoll, wenn Sie bereits mit einer serverseitigen Sprache arbeiten.
Code ansehen
// Select the button
const btn = document.querySelector(".btn-toggle");
// Listen for a click on the button
btn.addEventListener("click", function() {
// Toggle the .dark-theme class on the body
document.body.classList.toggle("dark-theme");
// Let's say the theme is equal to light
let theme = "light";
// If the body contains the .dark-theme class...
if (document.body.classList.contains("dark-theme")) {
// ...then let's make the theme dark
theme = "dark";
}
// Then save the choice in a cookie
document.cookie = "theme=" + theme;
});
Wir können nun prüfen, ob dieses Cookie existiert, und das entsprechende Theme laden, indem wir die richtige Klasse auf den <body>-Tag anwenden.
<?php
$themeClass = '';
if (!empty($_COOKIE['theme']) && $_COOKIE['theme'] == 'dark') {
$themeClass = 'dark-theme';
}
?>
<!DOCTYPE html>
<html lang="en">
<!-- etc. -->
<body class="<?php echo $themeClass; ?>">
<!-- etc. -->
</body>
</html>
So geht das mit der Methode der separaten Stylesheets
<?php
$themeStyleSheet = 'light-theme.css';
if (!empty($_COOKIE['theme']) && $_COOKIE['theme'] == 'dark') {
$themeStyleSheet = 'dark-theme.css';
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- etc. -->
<link href="<?php echo $themeStyleSheet; ?>" rel="stylesheet" id="theme-link">
</head>
<!-- etc. -->
Wenn Ihre Website über Benutzerkonten verfügt – also einen Bereich zum Einloggen und Verwalten von Profildaten –, ist dies ebenfalls ein hervorragender Ort, um Theme-Präferenzen zu speichern. Senden Sie diese an die Datenbank, in der die Kontodaten gespeichert sind. Wenn sich der Benutzer anmeldet, rufen Sie das Theme aus der Datenbank ab und wenden es mittels PHP (oder einem anderen serverseitigen Skript) auf die Seite an.
Es gibt verschiedene Wege, dies zu tun. In diesem Beispiel rufe ich die Theme-Präferenz des Benutzers aus der Datenbank ab und speichere sie zum Zeitpunkt des Logins in einer Session-Variablen.
<?php
// Login action
if (!empty($_POST['login'])) {
// etc.
// If the uuser is authenticated...
if ($loginSuccess) {
// ... save their theme preference to a session variable
$_SESSION['user_theme'] = $userData['theme'];
}
}
// Pick the session variable first if it's set; otherwise pick the cookie
$themeChoice = $_SESSION['user_theme'] ?? $_COOKIE['theme'] ?? null;
$themeClass = '';
if ($themeChoice == 'dark') {
$themeClass = 'dark-theme';
}
?>
<!DOCTYPE html>
<html lang="en">
<!-- etc. -->
<body class="<?php echo $themeClass; ?>">
<!-- etc. -->
</body>
</html>
Ich verwende den Null-Coalescing-Operator von PHP (??), um zu entscheiden, woher die Theme-Präferenz bezogen werden soll: aus der Session oder aus dem Cookie. Wenn der Benutzer eingeloggt ist, wird der Wert der Session-Variablen anstelle des Cookies genommen. Und wenn der Benutzer nicht eingeloggt ist oder sich ausgeloggt hat, wird der Wert des Cookies verwendet.
Umgang mit User-Agent-Styles
Um das UA-Stylesheet des Browsers über die systemweiten Farbschema-Präferenzen zu informieren und ihm mitzuteilen, welche Farbschemata auf der Seite unterstützt werden, können wir das Meta-Tag color-scheme verwenden.
Nehmen wir zum Beispiel an, die Seite soll sowohl „dark“ als auch „light“ Themes unterstützen. Wir können beide als Werte im Meta-Tag angeben, getrennt durch Leerzeichen. Wenn wir nur ein „helles“ Theme unterstützen wollen, müssen wir nur „light“ als Wert verwenden. Dies wird in einem CSSWG-GitHub-Issue diskutiert, in dem es ursprünglich vorgeschlagen wurde.
<meta name="color-scheme" content="dark light">
Wenn dieses Meta-Tag hinzugefügt wird, berücksichtigt der Browser die Farbschema-Präferenzen des Benutzers beim Rendern von UA-gesteuerten Elementen der Seite (wie etwa einem <button>). Er rendert Farben für den Hintergrund des Root-Elements, Formularsteuerelemente und Rechtschreibprüfungsfunktionen (sowie alle anderen UA-gesteuerten Stile) basierend auf der Präferenz des Benutzers.

Obwohl Themes größtenteils manuell gestaltet werden (was die UA-Styles überschreibt), hilft es, den Browser über die unterstützten Themes zu informieren, um selbst die geringste Chance auf eine potenzielle FOIT-Situation zu vermeiden. Dies gilt für jene Fälle, in denen das HTML bereits gerendert wurde, das CSS aber noch geladen wird.
Wir können dies auch in CSS festlegen
:root {
color-scheme: light dark; /* both supported */
}

Zum Zeitpunkt der Erstellung dieses Artikels mangelt es der Eigenschaft color-scheme noch an breiter Browserunterstützung, obwohl sowohl Safari als auch Chrome sie unterstützen.
Alles kombinieren!
Kombinieren wir alles und erstellen eine funktionierende Demo, die
- automatisch ein dunkles oder helles Theme basierend auf den Systemeinstellungen lädt
- es dem Benutzer ermöglicht, seine Systemeinstellung manuell zu überschreiben
- das bevorzugte Theme des Benutzers bei Seitenaktualisierungen beibehält
Verwendung von JavaScript & Local Storage
// Select the button
const btn = document.querySelector(".btn-toggle");
// Check for dark mode preference at the OS level
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
// Get the user's theme preference from local storage, if it's available
const currentTheme = localStorage.getItem("theme");
// If the user's preference in localStorage is dark...
if (currentTheme == "dark") {
// ...let's toggle the .dark-theme class on the body
document.body.classList.toggle("dark-mode");
// Otherwise, if the user's preference in localStorage is light...
} else if (currentTheme == "light") {
// ...let's toggle the .light-theme class on the body
document.body.classList.toggle("light-mode");
}
// Listen for a click on the button
btn.addEventListener("click", function() {
// If the user's OS setting is dark and matches our .dark-mode class...
if (prefersDarkScheme.matches) {
// ...then toggle the light mode class
document.body.classList.toggle("light-mode");
// ...but use .dark-mode if the .light-mode class is already on the body,
var theme = document.body.classList.contains("light-mode") ? "light" : "dark";
} else {
// Otherwise, let's do the same thing, but for .dark-mode
document.body.classList.toggle("dark-mode");
var theme = document.body.classList.contains("dark-mode") ? "dark" : "light";
}
// Finally, let's save the current preference to localStorage to keep using it
localStorage.setItem("theme", theme);
});
Verwendung von PHP & Cookies
<?php
$themeClass = '';
if (!empty($_COOKIE['theme'])) {
if ($_COOKIE['theme'] == 'dark') {
$themeClass = 'dark-theme';
} else if ($_COOKIE['theme'] == 'light') {
$themeClass = 'light-theme';
}
}
?>
<!DOCTYPE html>
<html lang="en">
<!-- etc. -->
<body class="<?php echo $themeClass; ?>">
<!-- etc. -->
<script>
const btn = document.querySelector(".btn-toggle");
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
btn.addEventListener("click", function() {
if (prefersDarkScheme.matches) {
document.body.classList.toggle("light-mode");
var theme = document.body.classList.contains("light-mode") ? "light" : "dark";
} else {
document.body.classList.toggle("dark-mode");
var theme = document.body.classList.contains("dark-mode") ? "dark" : "light";
}
document.cookie = "theme=" + theme;
});
</script>
</body>
</html>
Design-Überlegungen
Ich höre oft, dass die Implementierung des Dark Mode einfacher sei als dessen Gestaltung. Ohne das bewerten zu wollen, werfen wir einen Blick auf einige Überlegungen zur Gestaltung eines dunklen Themes.
Sie kennen bereits die grundlegende Aufgabe: helle Farbwerte durch dunklere ersetzen und umgekehrt. Aber es gibt einige UI-Elemente und Verfeinerungen, die nuancierter sind und mehr Aufmerksamkeit erfordern. Sehen wir uns diese an.
Bilder im Dark Mode
Eine gute Regel ist es, Helligkeit und Kontrast von Bildern etwas zu verringern, damit sie vor einem dunklen Hintergrund angenehm für die Augen wirken. Ein extrem helles Bild auf einem sehr dunklen Hintergrund kann störend wirken; das Abdunkeln des Bildes reduziert diesen starken Kontrast.


Die CSS-Funktion filter() ist bestens geeignet, dies für uns zu erledigen
/* Apply the filter directly on the body tag */
body.dark-theme img {
filter: brightness(.8) contrast(1.2);
}
/* Or apply it via media query */
@media (prefers-color-scheme: dark) {
img {
filter: brightness(.8) contrast(1.2);
}
}
Dasselbe können wir direkt im Markup tun, indem wir das <picture>-Element verwenden, um verschiedene Versionen eines Bildes zu laden
<picture>
<!-- Use this image if the user's OS setting is light or unset -->
<source srcset="photo-light.png" media="(prefers-color-scheme: light) or (prefers-color-scheme: no-preference)">
<!-- Use this image if the user's OS setting is dark -->
<source srcset="photo-dark.png" media="(prefers-color-scheme: dark)">
</picture>
Der Nachteil hierbei ist, dass zwei Dateien bereitgestellt werden müssen, während wir bei der CSS-Lösung nur mit einer arbeiten. Zudem wird hierbei nicht vollständig berücksichtigt, wenn der Benutzer das Farbschema auf der Seite manuell umschaltet.
Schatten im Dark Mode
Schatten im Dark Mode sind knifflig. Wenn wir einfach einen dunklen Schatten durch helle Farben invertieren, erhalten wir einen seltsamen Effekt mit einem hellen Schatten auf dunklem Hintergrund… und das sieht nicht gut aus.


Es ist möglich, einen dunklen Schatten im Dark Mode zu verwenden, aber die Hintergrundfarbe muss „hell“ genug sein (wie ein dunkles Grau), um genügend Kontrast zu bieten, damit man den Schatten überhaupt wahrnimmt.
🔥 Werfen Sie bei der Implementierung des Dark Mode nicht die visuellen Hinweise der hellen Version über Bord, indem Sie das Farbschema naiv invertieren.
— Steve Schoger (@steveschoger) 16. Juli 2019
Nahe Elemente sollten immer noch heller und entfernte Elemente immer noch dunkler sein – selbst in einer dunklen UI. pic.twitter.com/RNxgIppDmn
Verwenden Sie Opazität, um Tiefe zu vermitteln, wobei Regionen mit hoher Opazität eine geringere Tiefe haben. Das heißt, Elemente mit einer höheren Erhebung sollten eine geringere Opazität haben als Elemente, die in der Tiefe „näher“ am Hintergrund liegen.

Typografie im Dark Mode
Der Trick hier ist ähnlich wie bei Bildern: Wir müssen den Kontrast ausbalancieren. Eine zu fette Schrift führt zu grellem Text, der einen vom Bildschirm weichen lässt. Eine zu feine Schrift lässt uns die Augen anstrengen, während wir immer näher an den Bildschirm rücken.


Das Gleichgewicht liegt irgendwo in der Mitte. Robin hat einen schönen Artikel geschrieben, in dem er ein kleines Stück CSS vorschlägt, das einen großen Unterschied in der Lesbarkeit macht.
Icons im Dark Mode
Icons fallen in diese „knifflige“ Kategorie, da sie eine Mischung aus Text und Bild sind. Wenn wir mit SVG-Icons arbeiten, können wir jedoch die Füllung (fill) per CSS ändern. Wenn wir hingegen Icon-Fonts verwenden, können wir einfach die Farbgigenschaft (color) ändern.
/* SVG icon */
body.dark-theme svg.icon path {
fill: #efefef;
}
/* Font icon (using Font Awesome as an example) */
body.dark-theme .fa {
color: #efefef;
}
Viele der Design-Überlegungen, die für Text gelten, lassen sich generell auch auf Icons übertragen. Beispielsweise sollten wir reines Weiß und sehr dicke Umrisse vermeiden.
Farben im Dark Mode
Rein weißer Text auf rein schwarzem Hintergrund wirkt störend. Der Trick besteht darin, ein Off-White für den Text und ein Off-Black für den Hintergrund zu verwenden. Die Material Design Richtlinien empfehlen beispielsweise #121212 für den Hintergrund.


Farbpaletten im Dark Mode
Wir haben gesehen, welchen Unterschied die Verwendung von Off-White- und Off-Black-Farben für Text und Bilder macht. Bauen wir das mit Tipps zur Entwicklung einer vollständigen Farbpalette etwas aus.
Vieles lässt sich auf eines reduzieren: Kontrast. Deshalb ist der erste Tipp, bevor man sich auf eine Farbe festlegt, Ideen durch einen Kontrast-Checker laufen zu lassen. So wird sichergestellt, dass die Farbhältnisse den WCAG-Richtlinien für mindestens eine AA-Bewertung entsprechen, was einem Kontrastverhältnis von 4,5:1 entspricht.
Das bedeutet, dass entsättigte Farben unsere Freunde sind, wenn wir an einem Dark-Mode-Design arbeiten. Sie helfen, übermäßig grelle Bilder zu vermeiden und geben uns dennoch genügend Spielraum, um ein effektives Kontrastverhältnis zu schaffen.


Denken Sie als Nächstes daran, dass Akzentfarben zur Verfeinerung dienen. Sie sind wahrscheinlich heller als die Hintergrundfarbe des dunklen Themes. Wenn man sie also wie eine Primärfarbe oder als Hintergrundfarbe eines großen Containers verwendet, ist das für die Augen genauso störend und anstrengend wie ein helles Bild oder dicker weißer Text.


Wenn Kontrast das Gleichgewicht ist, das wir anstreben, dann denken Sie daran, dass der Dark Mode mehr als nur Schwarz und Grau ist. Wie wäre es mit einem dunkelblauen Hintergrund mit blassgelbem Text? Oder Dunkelbraun mit Beige? Es gibt ein ganzes (und wachsendes) Farbspektrum da draußen, und wir können jeden Teil davon nutzen, um die Kreativität anzuregen.
Einige Beispiele für Farben, die dunkel sind, ohne auf reines Schwarz zurückzugreifen
#232B32
#152028
#202945
Material Designs Leitfaden zum Dark Mode ist eine nützliche Ressource für Best Practices. Er ist definitiv lesenswert für weitere Tipps, die man im Hinterkopf behalten sollte.
Dark Mode in der Praxis
YouTube verwendet die Technik der CSS-Variablen. Sie haben alle ihre Farben in Variablen unter dem html-Selektor definiert, während Dark-Mode-Farben unter html:not(.style-scope)[dark] definiert sind. Wenn der Dark Mode aktiviert ist, fügt YouTube dem <html>-Tag ein Attribut dark="true" hinzu. Dies nutzen sie, um die im HTML definierten Variablen zu überschreiben.

<html> das Attribut dark=true hinzu, wenn es in den Dark Mode wechselt.In der Praxis scheint der Ansatz mit CSS Custom Properties am beliebtesten zu sein. Er wird von Dropbox Paper, Slack und Facebook verwendet.
Simplenote verwendet die Methode des Klassentauschs, bei der alle hellen Stilregeln Nachfahren einer Elternklasse .theme-light sind und alle dunklen Stile unter eine .theme-dark-Klasse fallen. Wenn das Theme umgeschaltet wird, wird die entsprechende Klasse auf den <body>-Tag angewendet.

.light-theme und .dark-theme, um die Themes zu gestalten.Twitter geht noch einen Schritt weiter und bietet mehrere Themes zur Auswahl an: „Standard“, „Dämmerung“ (Dim) und „Licht aus“ (Lights out). Die Option „Dämmerung“ verwendet Dunkelblau als Hintergrundfarbe. Im Vergleich dazu nutzt „Licht aus“ ein tiefes Schwarz.

Dark Mode oder kein Dark Mode? Das ist hier die Frage.
Es gibt auf beiden Seiten vollkommen berechtigte Gründe. Einige dieser Gründe gehen sogar über den Rahmen der User Experience hinaus und beinhalten Dinge wie Timing, Budget und Ressourcen.
Obwohl man berücksichtigen sollte, warum man einen Dark Mode eventuell nicht implementieren möchte, sind hier Gründe, die dafür sprechen:
- Es ist cool und trendy (obwohl das allein kein Grund ist, es zu tun).
- Es verbessert die Barrierefreiheit, indem es Nutzer unterstützt, die bei extrem hellen Themes empfindlich auf Augenbelastung reagieren.
- Es erlaubt den Nutzern, selbst über die angenehmste Art des Inhaltskonsums zu entscheiden, während wir gleichzeitig die Kontrolle über das Look-and-Feel behalten. Denken Sie daran: Wir wollen den Reader-Mode-Button schlagen!
- Es hilft, die Akkulaufzeit bei Geräten mit OLED-Bildschirmen zu schonen, bei denen hellere Farben mehr Energie verbrauchen.
- Es ist extrem beliebt und wird so schnell nicht verschwinden. Es ist wahrscheinlich, dass Ihre Nutzer, die einen Dark Mode bevorzugen (so wie ich!), erwarten, dass Ihre Seite einen hat. Man sollte also besser darauf vorbereitet sein.







Es ist auch erwähnenswert, dass Entwicklertools eine Option bieten, um zwischen Dark- und Light-Mode umzuschalten, ohne das Betriebssystem ändern zu müssen, falls Sie prüfen wollen, ob Ihre Erkennung funktioniert.
In Chromium-basierten Browsern (Microsoft Edge/Chrome/Brave...) können Sie dies im Rendering-Menü oder mit einem Tastaturkürzel tun.
https://docs.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/accessibility/preferred-color-scheme-simulation
Ja! Das wäre wirklich praktisch.
Es gibt ein Hauptproblem mit diesem Artikel: Alle beschriebenen Optionen erfordern JavaScript, um wirksam zu werden.
Eine viel bessere Technik für die clientseitige Auflösung des Dark Modes ist die Verwendung der tatsächlichen Media Query und die Anpassung dieser Media Query durch Ihren Umschalter, anstatt Klassen hinzuzufügen oder zu entfernen.
Das Endergebnis ist, dass der Dark Mode auch dann funktioniert, wenn JavaScript deaktiviert ist, und dass ein kurzes Aufblitzen des falschen Themes (Flash of Incorrect Theme) noch unwahrscheinlicher ist als zuvor.
Ich verwende diese Technik auf meiner eigenen Website und habe darüber unter https://chrismorgan.info/blog/dark-theme-implementation/ geschrieben.
Noch eine Sache: Dieses Beispiel ist nicht korrekt.
<picture>MUSS ein<img>-Kindelement haben, damit etwas angezeigt wird, falls keine der Quellen passt. So wie es jetzt ist, würden ältere Browser, die(prefers-color-scheme)nicht unterstützen, gar kein Bild erhalten. Außerdem könnten in Zukunft weitere Werte hinzugefügt werden; daher wärenot all and (prefers-color-scheme: dark)ohnehin besser als(prefers-color-scheme: light). (no-preferencewurde übrigens aus der Spezifikation entfernt; UAs verwenden jetzt standardmäßiglight.)Das Beispiel sollte also stattdessen so aussehen:
Hallo Chris,
das ist eine interessante Technik. Danke fürs Teilen. :)
Leider verstehe ich nicht ganz, wie genau das die FLIC-Situation verhindern würde, da man für die Modifikation der Query und alles andere immer noch JavaScript verwenden muss. Vielleicht übersehe ich etwas?!
Der Artikel spricht zwar über die Verwendung der
prefers-color-schemeMedia Query, um Systemeinstellungen zu berücksichtigen – was auch ohne JS funktionieren sollte. Dennoch kommt JS ins Spiel, wenn man dem Nutzer die manuelle Kontrolle über seine Theme-Präferenz geben möchte (d.h. die Systemeinstellung überschreiben).Du hast recht mit dem
<picture>-Tag. Das sieht viel besser aus! Danke für den Hinweis.Warum hat dieser Artikel keine Dark-Mode-Option? Pfft... :)
Nein. Das ist Dark Mode.
https://tonsky.me
:)
Das ist in der Tat eine clevere Dark-Mode-Implementierung!
Das ist der beste Dark Mode, den ich je gesehen habe :-)
Wirklich toller und detaillierter Artikel! :)
Ich denke jedoch, dass eine Möglichkeit fehlt, Themes nur mit CSS zu wechseln. Das könnte nützlich sein, da nicht jeder Zugriff auf JavaScript hat, oder einfach nur zum Spaß!
Ich habe vor einiger Zeit einen Beitrag darüber geschrieben, wie man das erreichen kann, was für einige Leser interessant sein könnte: https://alexandersandberg.com/theme-switcher/
Hier ist der Quellcode: https://github.com/alexandersandberg/theme-switcher
Es ist eine Technik, die Checkboxen (oder Radio-Buttons bei mehr als zwei Themes) und etwas CSS-Selektor-Magie nutzt, um zwischen den Themes zu wechseln. Sie ist zudem barrierefrei, was ein großes Plus ist.
Um die Theme-Präferenz des Nutzers zu speichern, ist leider immer noch ein kleines bisschen JavaScript erforderlich.
Hervorragender, umfassender Artikel, Kumpel!
Leider funktioniert die Demo „Combining all the things!“ in Firefox, aber nicht in Chrome.
Ich hatte das Betriebssystem bereits auf Dark Mode eingestellt (falls das Teil des Problems ist).
Mein Ansatz: [Light & Dark Mode mit Benutzer-Umschaltknopf](https://codepen.io/2kool2/pen/abzgPzJ)
Für einen „vollständigen“ Leitfaden fehlt der Hochkontrastmodus. Die forced-color-Abfrage ist hier unser Freund.
Nennen Sie es einfach Ultra Dark Mode; ein A11y-Thema klingt cool und passt zum Artikel.
Toller Artikel, ich liebe CSS Tricks!
Ich habe einen Blogpost darüber geschrieben, wie man Dark Mode mit React und React Hooks zusammen mit Styled Components umsetzt.
Schauen Sie sich den Post hier an, falls er hilfreich für Sie sein könnte.
Einige Dark-Mode-Links, die ich gespeichert habe...
Ihre reine CSS-Methode funktioniert perfekt mit Safari auf meinem iPhone. Ich bin mir nicht sicher, warum das zweite Beispiel mit JavaScript nicht funktioniert. Ich habe in meinem Browser nichts deaktiviert. Wie auch immer, ich schätze diesen prägnanten Artikel!
Das JavaScript-Beispiel funktioniert nicht, weil es eine Theme-Änderung von sich aus in der Art, wie der Code geschrieben ist, nicht erkennen kann. Der Teil zum Umschalten der Klassen würde nur einmal ausgeführt. Um jedes Mal umzuschalten, wenn sich das Theme ändert, fügen Sie den Code zum Umschalten der Klassen als Callback zum „onchange“-Event des Objekts „prefersDarkScheme“ hinzu, und alles würde reibungslos funktionieren.
Könnten Sie das bitte niederschreiben (coden)?
Damit wir mehr als einmal vom Gerät aus umschalten können :)
Außerdem bin ich neugierig, warum CSS-Tricks dieses Feature immer noch nicht hat, um Nutzer manuell umschalten zu lassen..((
Hallo! Sehr hilfreicher Artikel. Ich versuche gerade, einen Nachtmodus zu meiner Website hinzuzufügen, und bleibe beim Speichern der Nutzerpräferenz hängen.
Im Artikel funktioniert das Speichern der Nutzerpräferenz mit localStorage nur mit Methode #1 „Verwendung einer Body-Klasse“, aber wie lässt es sich mit Methode #2 „Verwendung separater Stylesheets“ umsetzen?
Ich versuche es umzusetzen, aber nichts ändert sich, da meine JS-Kenntnisse sehr gering sind. Können Sie mir helfen?
Toller Artikel!
Ich habe die Technik mit Cookies und serverseitiger Verarbeitung auf meiner WordPress-Website angewendet. Das funktionierte super – bis ich das Page-Caching aktiviert habe.
Die Website profitierte deutlich vom Page-Caching, aber das bedeutete, dass das Theme nicht „gespeichert“ wurde, d.h. bei jeder neuen Seite fing man wieder mit der gecachten Version von vorne an.
Ich habe mich also gefragt, ob es eine andere JavaScript-Methode ohne FOIT (Flash of Invisible Text) gibt. Da Tags ausgeführt werden, sobald sie angetroffen werden, ist eine meiner Ideen, einen Tag einzufügen, bevor die ganze Seite geladen ist, der den Cookie-Wert abruft und bei Bedarf eine Klasse hinzufügt. Wissen Sie, ob so etwas machbar ist?
Vielen Dank!
Ralph
Das ist vielleicht keine Frage zum Dark Mode. Aber kann mir jemand sagen, welches Tool in der Demo verwendet wird, bei dem man den vertikalen Balken verschieben kann, um den Links/Rechts-Vergleich zu sehen? Ich finde, das ist ein sehr cooler Effekt für eine Demo.
Ich glaube, das auf dieser Seite basiert auf Juxtapose ( https://juxtapose.knightlab.com ), aber es gibt eine ganze Reihe dieser Vorher/Nachher-Slider im Web, wie Cocoen und TwentyTwenty.
Um dieses „FLIC“ zu verhindern, könnte man eine Art Übergang (Transition) verwenden. Ich habe das vor ein paar Wochen gesehen, kann mich aber nicht erinnern, auf welcher Seite das war. Dennoch denke ich, dass das eine gute Lösung sein könnte – solange der Nutzer nicht „reduce-motion“ aktiviert hat...
Was bedeutet „FLIC“? Ich konnte nirgendwo finden, wofür „FLIC“ steht...
Hallo!
Ist es möglich, auch den Energiesparmodus zu erkennen?
Es gibt Videos, die nicht geladen werden, wenn mein iPhone im Stromsparmodus ist.
Es wäre interessant, eine Body-Klasse hinzuzufügen, wenn das Gerät im Energiesparmodus ist.
Danke hierfür, ein wirklich exzellenter Artikel, der alles enthielt, was ich für meinen aktuellen Website-Bau brauchte.
Gibt es eine Möglichkeit, die Duplizierung des CSS-Codes für die Media Query mit „prefers-color-scheme: dark“ zu vermeiden?
Das würde ich auch gerne wissen, Tomás. Unordentlich, wenn man ein halbes Dutzend Eigenschaften hat, ein Albtraum bei 100! Es muss einen besseren Weg geben...
Pure CSS: https://codepen.io/mori79/pen/ExwqNVv
Zugehöriger Post: https://stackoverflow.com/a/70811865/478018
Könnten Sie einen Artikel darüber schreiben, wie der Brave-Browser die komplette Farbpalette ändert, wenn wir den „Erzwungenen Dark Mode“ einschalten?
Wie würde ich eine Tabelle im Dark Mode bearbeiten? Ich versuche, den Rahmen der Tabelle in einer anderen Farbe als Schwarz darzustellen, scheine aber nicht das gewünschte Ergebnis zu erzielen. Danke!
Prüfen Sie, ob der Tabellenrahmen nicht direkt im HTML selbst festgelegt wird, und stylen Sie ihn dann im CSS.
Warum respektiert CSS-Tricks selbst die Dark-Mode-Präferenz nicht? Es gibt hier mehrere Artikel darüber, wie man ihn aktiviert, darunter einige, die sehr ins Detail gehen, aber im Moment ist der Hauptinhalt ein blendend weißes Rechteck.
Es ist auch gar nicht so weit entfernt. Es könnten etwa 8 Zeilen CSS in einer @media-Query sein und es würde einfach funktionieren. Bei mir funktioniert es gerade ziemlich gut mit nur ein paar Anpassungen in den Devtools. Ersetzen Sie den .wp-block-column Hintergrund durch eine halbtransparente Tönung, schalten Sie ein paar Resets aus, und dann müssen Sie gar nicht mehr viel Arbeit leisten.
Nun ist es vollbracht. Ich habe gerade ein Dark Theme mit Umschalter für eine Seite erstellt, kannte aber
prefers-color-schemenicht.Außerdem habe ich gerade mein Dark-Mode-Browser-Add-on gegen eines getauscht, das benutzerdefinierte Farben/CSS erlaubt.
Jetzt kann ich mein Farbschema für den System/Browser-Dark-Mode einstellen. Ich kann erreichen, dass jede Website, die ich besuche, dasselbe verwendet, und es trifft sich gut, dass es sich nicht zu sehr von meinem Desktop-Theme in Plasma unterscheidet.
Vereinheitlichung. Ich muss nur daran denken, es gelegentlich auszuschalten, damit ich sehe, wie die reale Welt aussieht.