Un sito decide tra chiaro e scuro in uno di due modi: la preferenza di sistema del visitatore, oppure una scelta esplicita che il sito memorizza per quel visitatore. I componenti di EmDash leggono entrambi i segnali tramite un’unica convenzione sull’elemento <html>. Questa pagina descrive tale convenzione, come dare a un campo immagine una variante scura e come renderizzarla con il componente Image di emdash/ui.
Convenzione del tema
I componenti e i template usano questi due segnali, in quest’ordine:
- Una classe
darkolightsu<html>fissa lo schema. La classe ha la precedenza sulla preferenza di sistema. - Senza classe, lo schema segue la media query
prefers-color-scheme.
I template inclusi memorizzano una scelta esplicita in un cookie theme e la applicano prima del primo rendering con uno script inline in <head>. Lo script seguente legge il cookie e imposta la classe, e non fa nulla quando non è memorizzata alcuna scelta:
<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 sola volta con light-dark() e lascia che sia la classe a fissare 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 selettore del tema non ha bisogno di alcuno script: lascia <html> senza classe e si applica la preferenza di sistema.
Varianti scure delle immagini
Un campo immagine può avere una seconda immagine per gli schemi di colore 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 del 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.
-
Fai clic su Add dark mode variant sotto l’immagine e scegli la controparte 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 finché 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 tramite CSS. Nel template non cambia nulla:
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { Image } from "emdash/ui";
const slug = decodeSlug(Astro.params.slug);
if (!slug) {
return Astro.rewrite("/404");
}
const { entry: post } = await getEmDashEntry("posts", slug);
if (!post) {
return Astro.rewrite("/404");
}
---
{post.data.featured_image && <Image image={post.data.featured_image} priority />}
L’output contiene due elementi <img>. L’immagine principale riceve la classe emdash-image--light e la variante riceve emdash-image--dark. Entrambe usano il testo alt dell’immagine principale, gli override di larghezza e altezza e gli attributi di caricamento. Ognuna mantiene il proprio colore segnaposto.
Un id che passi rimane sull’immagine principale; la variante riceve lo stesso id con il suffisso --dark, quindi id="hero" produce hero e hero--dark.
Quando l’immagine scura proviene da un’altra fonte, ad esempio 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 nascosta con display: none, quindi un visitatore scarica solo la variante per il proprio schema, e l’altra viene caricata quando lo schema cambia.
Con priority, entrambe le immagini ricevono loading="eager" e fetchpriority="high", ed entrambe vengono scaricate in ogni schema. Il tema viene deciso nel browser, quindi il server non può sapere quale variante vedrà un visitatore. Usa priority sull’unica immagine above-the-fold e lascia lazy le altre immagini.
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 tua regola che punta a <html> con una classe o un attributo ha la precedenza.
Se il tuo selettore imposta un attributo come data-theme, la soluzione più breve è impostare anche le classi dark e light dallo stesso percorso di codice. In caso contrario, sovrascrivi i quattro casi nel tuo foglio di stile:
: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;
}
Fai corrispondere il valore di display a quello che il tuo foglio di stile assegna altrove alle immagini, ad esempio inline quando non reimposti img a block.