Dunkelmodus

Auf dieser Seite

Eine Website entscheidet sich auf eine von zwei Arten zwischen hell und dunkel: die Systempräferenz des Besuchers oder eine explizite Wahl, die die Website für diesen Besucher speichert. EmDash-Komponenten lesen beide Signale über eine Konvention am <html>-Element. Diese Seite beschreibt diese Konvention, wie man einem Bildfeld eine dunkle Variante gibt und wie man sie mit der Image-Komponente aus emdash/ui rendert.

Theme-Konvention

Komponenten und Templates verwenden diese beiden Signale in dieser Reihenfolge:

  1. Eine dark- oder light-Klasse auf <html> fixiert das Schema. Die Klasse gewinnt über die Systempräferenz.
  2. Ohne Klasse folgt das Schema der prefers-color-scheme-Media-Query.

Die mitgelieferten Templates speichern eine explizite Wahl in einem theme-Cookie und wenden sie vor dem ersten Paint mit einem Inline-Skript im <head> an. Das folgende Skript liest das Cookie und setzt die Klasse und tut nichts, wenn keine Wahl gespeichert ist:

<script is:inline>
	(function () {
		var c = document.cookie;
		var i = c.indexOf("theme=");
		var theme = i >= 0 ? c.slice(i + 6).split(";")[0] : null;
		if (theme === "dark" || theme === "light") {
			document.documentElement.classList.add(theme);
		}
	})();
</script>

Definieren Sie Farben einmal mit light-dark() und lassen Sie die Klasse das Schema fixieren:

:root {
	color-scheme: light dark;
	--color-bg: light-dark(#ffffff, #0d0d0d);
	--color-text: light-dark(#1a1a1a, #ededed);
}
:root.light {
	color-scheme: light;
}
:root.dark {
	color-scheme: dark;
}

Eine Website ohne Theme-Umschalter benötigt kein Skript: Lassen Sie <html> ohne Klasse und die Systempräferenz gilt.

Dunkle Bildvarianten

Ein Bildfeld kann ein zweites Bild für dunkle Farbschemata tragen. Redakteure wählen es neben dem Primärbild aus, und die Image-Komponente zeigt das an, das zum Schema des Besuchers passt.

Den Slot an einem Feld aktivieren

Der Slot ist standardmäßig deaktiviert. Aktivieren Sie ihn pro Feld, entweder im Admin oder in einer Seed-Datei.

Im Admin öffnen Sie Content Types, bearbeiten das Bildfeld und schalten Dark mode variant ein.

In einer Seed-Datei setzen Sie die darkVariant-Widget-Option auf dem Feld:

{
	"slug": "featured_image",
	"label": "Featured Image",
	"type": "image",
	"options": { "darkVariant": true }
}

Die Variante im Editor auswählen

  1. Öffnen Sie einen Eintrag und wählen Sie das Primärbild wie gewohnt aus.

  2. Klicken Sie unter dem Bild auf Add dark mode variant und wählen Sie die dunkle Variante aus der Mediathek.

  3. Speichern Sie den Eintrag.

Die Variante wird innerhalb des Feldwerts als darkVariant gespeichert. Das Entfernen des Primärbildes entfernt auch die Variante; das Ersetzen des Primärbildes behält die Variante bei, bis Sie sie ersetzen oder entfernen.

Die Variante rendern

Die Image-Komponente rendert beide Bilder, wenn der Wert eine darkVariant enthält, und zeigt das passende mit CSS an. Im Template ändert sich nichts:

---
import { decodeSlug, getEmDashEntry } from "emdash";
import { Image } from "emdash/ui";

const slug = decodeSlug(Astro.params.slug);

if (!slug) {
  return Astro.redirect("/404");
}

const { entry: post } = await getEmDashEntry("posts", slug);

if (!post) {
  return Astro.redirect("/404");
}
---

{post.data.featured_image && <Image image={post.data.featured_image} priority />}

Die Ausgabe enthält zwei <img>-Elemente. Das Primärbild erhält die Klasse emdash-image--light und die Variante erhält emdash-image--dark. Beide verwenden den Alt-Text, die Breiten- und Höhenüberschreibungen sowie die Ladeattribute des Primärbildes. Jedes behält seine eigene Platzhalterfarbe.

Eine id, die Sie übergeben, bleibt auf dem Primärbild; die Variante erhält die gleiche id mit einem --dark-Suffix, sodass id="hero" hero und hero--dark ergibt.

Wenn das dunkle Bild von anderswo kommt, wie z.B. einem zweiten Bildfeld, übergeben Sie es explizit:

<Image image={post.data.hero} darkVariant={post.data.hero_dark} />

Ladeverhalten

Beide Bilder sind standardmäßig lazy. Browser laden ein lazy Bild, das mit display: none verborgen ist, nicht herunter, sodass ein Besucher nur die Variante für sein Schema herunterlädt und die andere geladen wird, wenn das Schema wechselt.

Mit priority erhalten beide Bilder loading="eager" und fetchpriority="high", und beide werden in jedem Schema heruntergeladen. Das Theme wird im Browser entschieden, sodass der Server nicht wissen kann, welche Variante ein Besucher sehen wird. Verwenden Sie priority für das eine Above-the-Fold-Bild und lassen Sie andere Bilder lazy.

Eine andere Theme-Konvention verwenden

Das mitgelieferte CSS verbirgt die Variante, die nicht zum Schema passt. Seine Selektoren verwenden :where() für den <html>-Teil, sodass jede Ihrer Regeln, die <html> mit einer Klasse oder einem Attribut anspricht, gewinnt.

Wenn Ihr Umschalter ein Attribut wie data-theme setzt, ist die kürzeste Lösung, auch die dark- und light-Klassen aus demselben Codepfad zu setzen. Andernfalls überschreiben Sie die vier Fälle in Ihrem eigenen Stylesheet:

:root[data-theme="dark"] .emdash-image--light,
:root[data-theme="light"] .emdash-image--dark {
	display: none;
}
:root[data-theme="dark"] .emdash-image--dark,
:root[data-theme="light"] .emdash-image--light {
	display: block;
}

Passen Sie den display-Wert an den an, den Ihr Stylesheet Bildern anderswo gibt, zum Beispiel inline, wenn Sie img nicht auf block zurücksetzen.