Un site choisit entre clair et sombre de deux manières : la préférence système du visiteur, ou un choix explicite que le site stocke pour ce visiteur. Les composants EmDash lisent les deux signaux via une convention sur l’élément <html>. Cette page décrit cette convention, comment donner à un champ image une variante sombre, et comment la rendre avec le composant Image de emdash/ui.
Convention de thème
Les composants et les templates utilisent ces deux signaux, dans cet ordre :
- Une classe
darkoulightsur<html>fixe le schéma. La classe l’emporte sur la préférence système. - Sans classe, le schéma suit la media query
prefers-color-scheme.
Les templates fournis stockent un choix explicite dans un cookie theme et l’appliquent avant le premier affichage avec un script en ligne dans <head>. Le script suivant lit le cookie et définit la classe, et ne fait rien quand aucun choix n’est stocké :
<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>
Définissez les couleurs une fois avec light-dark() et laissez la classe fixer le schéma :
: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 site sans commutateur de thème n’a pas besoin de script : laissez <html> sans classe et la préférence système s’applique.
Variantes d’image sombres
Un champ image peut porter une seconde image pour les schémas de couleurs sombres. Les éditeurs la choisissent à côté de l’image principale, et le composant Image affiche celle qui correspond au schéma du visiteur.
Activer le slot sur un champ
Le slot est désactivé par défaut. Activez-le par champ, soit dans l’admin, soit dans un fichier seed.
Dans l’admin, ouvrez Content Types, éditez le champ image et activez Dark mode variant.
Dans un fichier seed, définissez l’option de widget darkVariant sur le champ :
{
"slug": "featured_image",
"label": "Featured Image",
"type": "image",
"options": { "darkVariant": true }
}
Choisir la variante dans l’éditeur
-
Ouvrez une entrée et sélectionnez l’image principale comme d’habitude.
-
Cliquez sur Add dark mode variant sous l’image et choisissez la variante sombre dans la bibliothèque multimédia.
-
Enregistrez l’entrée.
La variante est stockée dans la valeur du champ en tant que darkVariant. Supprimer l’image principale supprime la variante avec elle ; remplacer l’image principale conserve la variante jusqu’à ce que vous la remplaciez ou la supprimiez.
Rendre la variante
Le composant Image rend les deux images quand la valeur contient une darkVariant et affiche celle qui correspond avec CSS. Rien ne change dans le 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 />}
La sortie contient deux éléments <img>. L’image principale reçoit la classe emdash-image--light et la variante reçoit emdash-image--dark. Les deux utilisent le texte alternatif, les remplacements de largeur et hauteur, et les attributs de chargement de l’image principale. Chacune garde sa propre couleur de remplacement.
Un id que vous passez reste sur l’image principale ; la variante reçoit le même id avec un suffixe --dark, donc id="hero" donne hero et hero--dark.
Quand l’image sombre vient d’ailleurs, comme un second champ image, passez-la explicitement :
<Image image={post.data.hero} darkVariant={post.data.hero_dark} />
Comportement de chargement
Les deux images sont lazy par défaut. Les navigateurs ne téléchargent pas une image lazy qui est masquée avec display: none, donc un visiteur ne télécharge que la variante pour son schéma, et l’autre se charge quand le schéma change.
Avec priority, les deux images reçoivent loading="eager" et fetchpriority="high", et les deux sont téléchargées dans chaque schéma. Le thème est décidé dans le navigateur, donc le serveur ne peut pas savoir quelle variante un visiteur verra. Utilisez priority sur l’unique image au-dessus de la ligne de flottaison et laissez les autres images en lazy.
Utiliser une convention de thème différente
Le CSS fourni masque la variante qui ne correspond pas au schéma. Ses sélecteurs utilisent :where() sur la partie <html>, donc toute règle de votre part qui cible <html> avec une classe ou un attribut l’emporte.
Si votre commutateur définit un attribut comme data-theme, la solution la plus courte est de définir aussi les classes dark et light depuis le même chemin de code. Sinon, surchargez les quatre cas dans votre propre feuille de styles :
: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;
}
Faites correspondre la valeur display à celle que votre feuille de styles donne aux images ailleurs, par exemple inline quand vous ne réinitialisez pas img à block.