Un site choisit entre clair et sombre de l’une de deux façons : la préférence système du visiteur, ou un choix explicite que le site enregistre pour ce visiteur. Les composants EmDash lisent ces deux signaux au moyen d’une seule convention sur l’élément <html>. Cette page décrit cette convention, comment donner une variante sombre à un champ d’image 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>impose 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 enregistrent un choix explicite dans un cookie theme et l’appliquent avant le premier rendu grâce à un script en ligne dans <head>. Le script suivant lit le cookie et définit la classe, et ne fait rien lorsqu’aucun choix n’est enregistré :
<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 seule fois avec light-dark() et laissez la classe imposer 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 sélecteur de thème n’a besoin d’aucun script : laissez <html> sans classe et la préférence système s’applique.
Variantes d’image sombres
Un champ d’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 champ par champ, soit dans l’admin, soit dans un fichier seed.
Dans l’admin, ouvrez Content Types, modifiez le champ d’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 contrepartie sombre dans la médiathèque.
-
Enregistrez l’entrée.
La variante est stockée dans la valeur du champ sous le nom darkVariant. Supprimer l’image principale supprime aussi la variante ; 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 lorsque la valeur porte une darkVariant et affiche celle qui correspond grâce au 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.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 />}
Le résultat contient deux éléments <img>. L’image principale reçoit la classe emdash-image--light et la variante reçoit emdash-image--dark. Toutes deux utilisent le texte alt de l’image principale, les surcharges de largeur et de hauteur, ainsi que les attributs de chargement. Chacune conserve sa propre couleur d’espace réservé.
Un id que vous passez reste sur l’image principale ; la variante reçoit le même id avec le suffixe --dark, de sorte que id="hero" produit hero et hero--dark.
Lorsque l’image sombre vient d’ailleurs, par exemple d’un second champ d’image, passez-la explicitement :
<Image image={post.data.hero} darkVariant={post.data.hero_dark} />
Comportement de chargement
Les deux images sont en chargement différé par défaut. Les navigateurs ne récupèrent pas une image différée masquée par display: none, de sorte qu’un visiteur ne télécharge que la variante correspondant à son schéma, et l’autre se charge lorsque le schéma change.
Avec priority, les deux images reçoivent loading="eager" et fetchpriority="high", et les deux sont téléchargées quel que soit le schéma. Le thème est décidé dans le navigateur ; le serveur ne peut donc pas savoir quelle variante un visiteur verra. Utilisez priority sur l’unique image située au-dessus de la ligne de flottaison et laissez les autres images en chargement différé.
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>, de sorte que toute règle de votre cru qui cible <html> avec une classe ou un attribut l’emporte.
Si votre sélecteur définit un attribut tel que data-theme, la solution la plus courte consiste à 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 style :
: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;
}
Alignez la valeur de display sur celle que votre feuille de style donne aux images ailleurs, par exemple inline lorsque vous ne réinitialisez pas img en block.