Die Kurzfassung
- Ein Theme mit CSS-Variablen funktioniert am besten in zwei Ebenen: Palettenvariablen mit rohen Farben und semantische Variablen, die beschreiben, wofür jede Farbe da ist.
- Komponenten sollten nur semantische Variablen wie --color-text oder --color-surface lesen, nie direkt Palettenwerte.
- Der Dunkelmodus besteht dann darin, die semantischen Variablen unter einer Media Query oder einem Data-Attribut auf andere Palettenwerte zu verweisen.
- Die Funktion light-dark() und die Eigenschaft color-scheme lassen eine Deklaration in aktuellen Browsern beide Modi halten.
- Ein kleines Inline-Skript im head, das das gespeicherte Theme setzt, bevor die Seite gezeichnet wird, verhindert das Aufblitzen des falschen Themes.
Auf dieser Seite
Ein Theme mit CSS-Variablen ist eine Gruppe von Custom Properties wie --color-surface und --color-text, die jede Komponente statt fest kodierter Farben liest. Um das Theme zu wechseln, änderst du die Variablen, meist auf :root oder an einem data-theme-Attribut, und das ganze Interface folgt. Der Trick, der es skalierbar macht, ist die Aufteilung der Variablen in zwei Ebenen: eine Palette roher Farben und semantische Rollen, die auf diese Palette verweisen.
Zwei Ebenen: Palette und Rollen
Palettenvariablen sind danach benannt, was sie sind: --violet-600, --ink-900. Semantische Variablen sind danach benannt, was sie tun: --color-accent, --color-text-muted. Komponenten lesen nur die zweite Art. Kommt der Dunkelmodus, verweist du die Rollen neu und lässt jede Komponente unberührt. Das ist dieselbe Idee wie bei Design Tokens, direkt in CSS ausgedrückt.
--violet-600: #7c3aedWer sie liest
Ändert sich, wenn
--color-accent: var(--violet-600)Wer sie liest
Ändert sich, wenn
Beispiel
--button-bg: var(--color-accent)Wer sie liest
Ändert sich, wenn
:root {
/* Palette: raw values, named for what they are */
--paper-50: #faf8f5;
--paper-100: #f1ede6;
--ink-900: #14121f;
--ink-700: #3d3a4f;
--ink-500: #6b6880;
--violet-600: #6d28d9;
--violet-300: #c4b5fd;
--night-950: #0d0b16;
--night-900: #17142a;
--night-800: #221e3a;
/* Roles: what each colour is for (light mode) */
--color-bg: var(--paper-50);
--color-surface: var(--paper-100);
--color-text: var(--ink-900);
--color-text-muted: var(--ink-500);
--color-border: color-mix(in oklab, var(--ink-900) 12%, transparent);
--color-accent: var(--violet-600);
--color-on-accent: #ffffff;
}
body { background: var(--color-bg); color: var(--color-text); }
.card { background: var(--color-surface); border: 1px solid var(--color-border); }
.button { background: var(--color-accent); color: var(--color-on-accent); }Rollennamen, die ein Redesign überleben
Ein Rollenname sollte auch nach einer Farbänderung noch stimmen. --light-grey ist im Dunkelmodus nicht mehr hell, und --blue lügt an dem Tag, an dem die Marke grün wird. Benenne stattdessen die Aufgabe und das Paar, damit die nächste Person, die das Stylesheet liest, weiß, welche Farbe auf welche gehört.
Namen, die brechen
--blue,--purple-button--light-grey-bg--white-text--dark-border
Namen, die halten
--color-accent,--color-on-accent--color-surface--color-text--color-border
Dunkelmodus mit CSS-Variablen ergänzen
Der Dunkelmodus verweist die Rollen neu. Respektiere standardmäßig die Einstellung des Betriebssystems und lass ein data-theme-Attribut sie überschreiben, wenn der Leser selbst wählt. Setz auch color-scheme, damit Scrollbalken, Formularelemente und die Standardfläche passen.
:root { color-scheme: light; }
/* Follow the system unless the reader picked light */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
color-scheme: dark;
--color-bg: var(--night-950);
--color-surface: var(--night-900);
--color-text: #f2f0fa;
--color-text-muted: #a5a1bd;
--color-border: color-mix(in oklab, #ffffff 12%, transparent);
--color-accent: var(--violet-300);
--color-on-accent: var(--ink-900);
}
}
/* The reader picked dark explicitly */
:root[data-theme="dark"] {
color-scheme: dark;
--color-bg: var(--night-950);
--color-surface: var(--night-900);
--color-text: #f2f0fa;
--color-text-muted: #a5a1bd;
--color-border: color-mix(in oklab, #ffffff 12%, transparent);
--color-accent: var(--violet-300);
--color-on-accent: var(--ink-900);
}light-dark() beseitigt die Wiederholung.Der Dunkelmodus ist kein invertierter Hellmodus. Flächen werden heller, je höher sie liegen, Akzente hellen auf, und Schatten weichen Rahmen. Dark-Mode-Design und Verläufe im Dark Mode behandeln die visuelle Seite.
Die Abkürzung light-dark()
Aktuelle Browser unterstützen light-dark(), das einen hellen und einen dunklen Wert nimmt und anhand des color-scheme des Elements einen davon wählt. Setz color-scheme: light dark auf das Root-Element, um dem System zu folgen, oder erzwinge einen Modus über das Attribut, und jede Rolle wird zu einer einzigen Zeile: --color-bg: light-dark(var(--paper-50), var(--night-950)). Behalte die längere Form, wenn du Browser von vor 2024 unterstützen musst.
Ein Theme-Umschalter ohne Aufblitzen
Wird die gespeicherte Wahl erst nach dem Rendern der Seite angewendet, sehen Leser, die Dunkel gewählt haben, bei jedem Laden ein weißes Aufblitzen. Setz das Attribut in einem winzigen Inline-Skript im head, bevor ein Stylesheet den Body zeichnet.
<head>
<script>
(function () {
var saved = localStorage.getItem("theme");
if (saved === "light" || saved === "dark") {
document.documentElement.dataset.theme = saved;
}
})();
</script>
<link rel="stylesheet" href="/styles.css">
</head>dataset.theme setzen und den Wert in localStorage speichern.- 1
Biete drei Optionen an
Hell, dunkel und System. Entfernst du das Attribut, übernimmt wieder
prefers-color-scheme. - 2
Speichere nur ausdrückliche Wahlen
Speichere
lightoderdark; lösche den Schlüssel für System, damit eine spätere Änderung im Betriebssystem respektiert wird. - 3
Vermeide Übergänge beim Laden
Wenn Farben animiert wechseln, aktiviere den Übergang erst nach dem ersten Zeichnen, sonst animiert die Seite beim Laden von hell nach dunkel.
Marken-Themes jenseits von hell und dunkel
Dieselben zwei Ebenen tragen mehrere Marken in einer Codebasis. Jede Marke liefert unter einem data-brand-Attribut eigene Paletten- und Rollenwerte, und die Modi funktionieren weiter darüber. Mit color-mix() leitest du Hover-Zustände und helle Töne aus einem Akzent pro Marke ab, wie color-mix() in CSS zeigt.
[data-brand="harbour"] {
--color-accent: #0f766e;
--gradient-hero: linear-gradient(150deg, #042f2e 0%, #0f766e 55%, #5eead4 100%);
}
[data-brand="ember"] {
--color-accent: #c2410c;
--gradient-hero: linear-gradient(150deg, #431407 0%, #c2410c 55%, #fdba74 100%);
}
.button:hover { background: color-mix(in oklab, var(--color-accent), black 12%); }
.hero { background: var(--gradient-hero); }Weil Custom Properties vererbt werden, muss ein Theme nicht die ganze Seite abdecken. Setz data-theme="dark" auf einen Abschnitt, etwa ein Werbeband oder einen Footer, und alles darin liest die dunklen Rollen, während der Rest der Seite hell bleibt. Schreib den dunklen Selektor dafür als [data-theme="dark"] statt :root[data-theme="dark"] und setz color-scheme auch am Abschnitt.
Web und Designs auf einer Palette halten
Ein Theme in CSS ist nur die Hälfte einer Marke. Dieselben Farben sollten in deinen Social Posts, Präsentationen und E-Mails auftauchen. Das Markenkit von Gradiently hält deine Paletten, Logos und Schriften für Überschriften und Fließtext, und der Designer wendet es an, wenn er ein Design setzt, sodass der Post vom Montag denselben Akzent nutzt wie deine Website. Wenn du diese Farben noch auswählst, starte mit Markenfarben wählen.
Häufige Fragen
Wie baue ich ein Theme mit CSS-Variablen?
Definiere Palettenvariablen mit rohen Farben und dann semantische Variablen wie --color-bg, die auf sie verweisen. Komponenten lesen nur die semantischen, und Themes verweisen sie neu.
Wie ergänze ich einen Dunkelmodus mit CSS-Variablen?
Überschreib die semantischen Variablen in @media (prefers-color-scheme: dark) und unter einem Selektor [data-theme="dark"] für Leser, die ihn wählen.
Wie verhindere ich, dass das Theme beim Laden aufblitzt?
Lies das gespeicherte Theme in einem kleinen Inline-Skript im head und setz das Attribut, bevor das Stylesheet die Seite zeichnet.
Was macht light-dark() in CSS?
Es liefert im Hellmodus seinen ersten und im Dunkelmodus seinen zweiten Wert, anhand des color-scheme des Elements. Es funktioniert in aktuellen großen Browsern.
Kann ich einen Verlauf in einer CSS-Variable speichern?
Ja. Speichere den ganzen Verlauf als Wert und nutze ihn in background. Um zwischen Verläufen zu animieren, registriere die Farbstopps mit @property.
Geschrieben von Gradiently
Das Team hinter Gradiently, einem Designtool rund um Marks: lebendige Farbverläufe, durch die alles, was du gestaltest, nach dir aussieht.
Unser Profil ansehen