Un sito decide tra chiaro e scuro in uno dei due modi: la preferenza di sistema del visitatore, o una scelta esplicita che il sito memorizza per quel visitatore. I componenti EmDash leggono entrambi i segnali attraverso una convenzione sull’elemento <html>. Questa pagina descrive quella convenzione, come dare a un campo immagine una variante scura, e come renderizzarla con il componente Image da emdash/ui.
Convenzione del tema
I componenti e i template usano questi due segnali, in questo ordine:
- Una classe
darkolightsu<html>fissa lo schema. La classe vince sulla preferenza di sistema. - Senza classe, lo schema segue la media query
prefers-color-scheme.
I template forniti memorizzano una scelta esplicita in un cookie theme e la applicano prima del primo rendering con uno script inline nel <head>. Lo script seguente legge il cookie e imposta la classe, e non fa nulla quando nessuna scelta è memorizzata:
<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>
Definisci i colori una volta con light-dark() e lascia che la classe fissi lo schema:
: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;
}
Un sito senza commutatore di tema non ha bisogno di script: lascia <html> senza classe e si applica la preferenza di sistema.
Varianti scure delle immagini
Un campo immagine può portare una seconda immagine per gli schemi di colori scuri. Gli editor la scelgono accanto all’immagine principale, e il componente Image mostra quella che corrisponde allo schema del visitatore.
Abilitare lo slot su un campo
Lo slot è disattivato per impostazione predefinita. Attivalo per campo, nell’admin o in un file seed.
Nell’admin, apri Content Types, modifica il campo immagine e attiva Dark mode variant.
In un file seed, imposta l’opzione widget darkVariant sul campo:
{
"slug": "featured_image",
"label": "Featured Image",
"type": "image",
"options": { "darkVariant": true }
}
Scegliere la variante nell’editor
-
Apri una voce e seleziona l’immagine principale come al solito.
-
Clicca su Add dark mode variant sotto l’immagine e scegli la variante scura dalla libreria multimediale.
-
Salva la voce.
La variante è memorizzata all’interno del valore del campo come darkVariant. Rimuovere l’immagine principale rimuove anche la variante; sostituire l’immagine principale mantiene la variante fino a quando non la sostituisci o la rimuovi.
Renderizzare la variante
Il componente Image renderizza entrambe le immagini quando il valore contiene una darkVariant e mostra quella corrispondente con CSS. Nulla cambia nel template:
---
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 />}
L’output contiene due elementi <img>. L’immagine principale ottiene la classe emdash-image--light e la variante ottiene emdash-image--dark. Entrambe usano il testo alternativo, le sovrascritture di larghezza e altezza, e gli attributi di caricamento dell’immagine principale. Ognuna mantiene il proprio colore segnaposto.
Un id che passi rimane sull’immagine principale; la variante ottiene lo stesso id con un suffisso --dark, quindi id="hero" produce hero e hero--dark.
Quando l’immagine scura viene da un’altra fonte, come un secondo campo immagine, passala esplicitamente:
<Image image={post.data.hero} darkVariant={post.data.hero_dark} />
Comportamento di caricamento
Entrambe le immagini sono lazy per impostazione predefinita. I browser non scaricano un’immagine lazy che è nascosta con display: none, quindi un visitatore scarica solo la variante per il suo schema, e l’altra si carica quando lo schema cambia.
Con priority, entrambe le immagini ottengono loading="eager" e fetchpriority="high", e entrambe vengono scaricate in ogni schema. Il tema è deciso nel browser, quindi il server non può sapere quale variante un visitatore vedrà. Usa priority sull’unica immagine above-the-fold e lascia le altre immagini lazy.
Usare una convenzione di tema diversa
Il CSS fornito nasconde la variante che non corrisponde allo schema. I suoi selettori usano :where() sulla parte <html>, quindi qualsiasi regola tua che punti a <html> con una classe o un attributo vince.
Se il tuo commutatore imposta un attributo come data-theme, la soluzione più breve è impostare anche le classi dark e light dallo stesso percorso di codice. Altrimenti, sovrascrivi i quattro casi nel tuo 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;
}
Abbina il valore display a quello che il tuo stylesheet dà alle immagini altrove, per esempio inline quando non resetti img a block.