Un bouton d'activation/de désactivation du mode sombre permet aux utilisateurs de remplacer le jeu de couleurs du système pour un site.
Le remplacement est appliqué en mettant à jour <meta name="color-scheme"> : light dark signifie "suivre la préférence système", light ou dark épinglent un schéma explicite.
Les couleurs (light-dark()), les couleurs système et l'UI native dépendent toutes de la propriété CSS color-scheme. Le bouton d'activation/de désactivation fonctionne donc en synchronisant cette propriété avec <meta> (voir Refléter le remplacement dans le CSS).
Bouton d'activation/désactivation persistant, contrôle des paramètres ou aucun bouton ?
La plupart des sites n'ont pas besoin d'un bouton d'activation/de désactivation persistant du jeu de couleurs dans l'UI du site (en-tête, navigation, pied de page, etc.). Suivez les préférences système par défaut et, si un remplacement manuel est nécessaire, placez la commande dans une surface de paramètres distincte : une page, un panneau ou une superposition de paramètres.
Épingler un thème à l'OS est une intention légitime, mais rare. Les intentions rares doivent être placées derrière une divulgation progressive, et non dans une commande visible à tout moment.
Les boutons d'activation/désactivation persistants se trouvent principalement sur les sites destinés aux développeurs ou aux personnes travaillant avec eux (par exemple, les concepteurs), où le changement de thème est une tâche beaucoup plus fréquente que pour l'utilisateur Web moyen. N'en ajoutez PAS un simplement parce qu'il s'agit d'un modèle courant sur les sites de développeurs : l'intérêt du développeur pour ce contrôle n'est pas représentatif des utilisateurs types.
Implémentation
Tout d'abord, suivez toutes les étapes de la section Mode sombre pour prendre en charge les deux thèmes, en utilisant par défaut les préférences système.
Modèle de données
Le modèle de données pour le bouton d'activation/de désactivation du mode sombre comprend généralement trois états :
- Système (aucune valeur stockée) : l'UI suit le jeu de couleurs du système. Idéalement, il devrait s'agir de l'option par défaut.
- Clair (stocké sous la forme
"light") : l'UI utilise le thème clair, quel que soit le jeu de couleurs du système. - Sombre (stocké sous la forme
"dark") : l'UI utilise le thème sombre, quel que soit le jeu de couleurs du système.
Cet état est généralement stocké dans localStorage et reflété dans un élément <meta name="color-scheme"> de l'en-tête du document.
Refléter le remplacement dans le CSS
La propriété <meta> n'est qu'une indication de présentation : toute déclaration color-scheme dans le CSS de l'auteur la remplace.
Étant donné que le mode sombre définit color-scheme: light dark sur :root, la mise à jour de <meta> seule est une opération sans effet, car le CSS l'emporte.
Mappez à nouveau <meta> à la propriété pour que la cascade la suive :
:root {
color-scheme: light dark;
&:has(> head > meta[name="color-scheme"][content="dark"]) {
color-scheme: dark;
}
&:has(> head > meta[name="color-scheme"][content="light"]) {
color-scheme: light;
}
}
NE codez PAS color-scheme: light ou color-scheme: dark en dur comme racine par défaut. La déclaration de base DOIT rester light dark.
Le CSS NE DOIT PAS dépendre du JS : si le JS ne s'exécute jamais, <meta> reste light dark et le site suit les préférences système. Rien ne se casse.
Persistance et prévention du FOUC
Conservez le remplacement dans localStorage. Supprimez l'entrée lorsque vous revenez à la valeur par défaut du système.
Pour éviter que le mauvais thème ne s'affiche brièvement, appliquez la valeur stockée dans un script intégré (PAS type=module, PAS defer) placé immédiatement après l'élément <meta> :
<meta name="color-scheme" content="light dark">
<script>
document.querySelector('meta[name="color-scheme"]').content = localStorage.getItem("color-scheme") ?? "light dark";
</script>
- Ce script intégré n'existe que pour empêcher le FOUC. Faites en sorte qu'il soit aussi petit que possible. Le code JS supplémentaire permettant de gérer le changement de jeu de couleurs peut être chargé ultérieurement.
- Dans de rares cas, l'accès à
localStoragepeut générer une erreur (par exemple, si les données du site sont bloquées). Toutefois, comme ce script ne fait rien d'autre, le seul effet secondaire serait une erreur de console. Encapsulez-les danstry .. catchsi cela est important. Assurez-vous que le thème est toujours appliqué à la page, même s'il ne peut pas être conservé. - Le remplacement peut changer depuis un autre onglet : gérez l'événement
storagedewindowpour rester synchronisé. - NE PAS utiliser
matchMedia()pour supprimer la valeur stockée lorsque la préférence système change pour correspondre à celle-ci. L'OS de nombreux utilisateurs change automatiquement de thème en fonction de l'heure de la journée. Supprimer la valeur stockée chaque fois que les deux coïncident empêcherait d'épingler un thème.
Branchement pour les valeurs HTML et non colorées
Les couleurs ne nécessitent aucun travail supplémentaire : une fois que <meta> est mappé à color-scheme (ci-dessus), light-dark() suit le remplacement.
Cette section explique comment adapter d'autres valeurs (par exemple, font-weight, les sources multimédias, etc.).
Lorsque la page suit simplement les préférences système, (prefers-color-scheme: dark) peut être utilisé pour le branchement, y compris dans les sources <picture> ou <video>.
Le remplacement du jeu de couleurs ajoute une complication supplémentaire : la préférence système n'est plus la source de vérité, et il n'existe pas d'alternative directe pour les API qui n'acceptent que les requêtes média.
Ne vous fiez PAS exclusivement aux classes appliquées par JS comme .dark pour le branchement, car elles seront incorrectes si JS ne se charge pas et que le thème par défaut de l'OS est sombre.
Vous pouvez combiner la requête média avec un sélecteur :root:has(> head > meta[name="color-scheme"][content="dark"]) (ou light) pour créer une branche.
Pour savoir comment implémenter cela de manière élégante, consultez Combinaisons de sélecteurs et de règles @.
Les options de la commande sont également des branches sans couleur : incluez les deux états dans le balisage (icône et texte d'action masqué visuellement, par exemple "Passer au thème sombre") et masquez l'état inactif à l'aide de ces sélecteurs.
display: none supprime également l'option redondante de la TA, de sorte que le contrôle n'a pas besoin de JS pour rester à jour lorsque la préférence système change.
Pour les contenus multimédias intégrés au code HTML, la seule solution consiste actuellement à inclure les deux versions en tant qu'éléments distincts et à activer/désactiver la visibilité de manière appropriée.
Le masquage des éléments <source> avec display: none ne fonctionne pas.
Interface utilisateur
Deux ou trois ?
Dans tous les cas, l'UI DOIT permettre de rétablir ou de définir le jeu de couleurs sur "Système".
Privilégiez l'affichage de deux états dans les boutons d'activation/désactivation dont l'espace est limité, comme les boutons d'activation/désactivation persistants dans l'interface du site (en-tête, navigation, pied de page, etc.) où l'espace est limité et où la modification des paramètres est généralement orthogonale à l'objectif de l'utilisateur.
Un contrôle de jeu de couleurs dans une surface de paramètres distincte (page, panneau ou superposition) est un scénario différent et PEUT exposer explicitement les trois états ("Clair", "Sombre", "Système") : l'utilisateur prend déjà des décisions délibérées sur le comportement futur, et il y a de la place pour expliquer les options.
Trois états explicites sont également justifiés si le site implémente des schémas contextuels (par exemple, un mode clair plus sombre lorsque l'OS est en mode sombre), car "Clair" et "Système (actuellement clair)" sont alors réellement différents.
Boutons d'activation/de désactivation à deux états
Lorsqu'un tel contrôle est utilisé, il s'agit généralement d'un ajustement temporaire du confort ("il y a trop de lumière en ce moment"), plutôt que de s'assurer que l'état actuel est conservé à long terme. Par conséquent, pour les boutons à deux états, il suffit d'afficher deux des trois paramètres : le système (pour que le paramètre puisse être rétabli) et l'opposé actuel du système, stocké en tant que valeur littérale actuelle.
Les deux seuls états doivent être :
- Paramètre système par défaut : aucune valeur stockée, contenu
<meta>light dark. Affiché sous sa valeur résolue actuelle (par exemple, une icône de soleil lorsqu'il fait jour). - Remplacement : stocké littéralement sous la forme
lightoudark.
Il s'agit essentiellement d'un contrôle à trois états (light dark, light, dark) où l'état explicite correspondant à la préférence système actuelle est inaccessible.
Lorsque l'utilisateur active ou désactive :
- Thème cible = l'opposé du thème actuellement affiché (valeur stockée, le cas échéant, sinon préférence système). L'intention de l'utilisateur est de "sélectionner l'opposé de ce que je vois actuellement", et NON de "sélectionner l'inverse de la valeur par défaut du système".
- Si la cible diffère de la préférence système actuelle, stockez-la littéralement.
- Si la cible correspond à la préférence système actuelle, l'utilisateur annule son ajustement : supprimez la valeur stockée. Ne le stockez PAS, car cela figerait le schéma de manière invisible et empêcherait les futures modifications du système.
- Définissez le contenu de
<meta>sur la valeur stockée, ou surlight darks'il n'y en a pas.
IMPORTANT : La divergence ne doit être vérifiée qu'au moment du stockage, jamais de manière rétroactive. Une valeur stockée que la préférence système modifie ultérieurement pour qu'elle corresponde DOIT être conservée. L'OS de nombreux utilisateurs change automatiquement de thème en fonction de l'heure de la journée. Supprimer la valeur stockée chaque fois que les deux coïncident empêcherait d'épingler un thème.
Exemple de scénario, en commençant par l'OS défini sur le thème clair :
- Les boutons d'activation/désactivation de l'utilisateur. Le thème sombre est différent de la préférence système.
darkest donc stocké et le site passe en mode sombre. - Le paramètre de l'OS passe au mode sombre. Le site reste sombre (la valeur stockée correspond désormais à la préférence système, mais elle est conservée).
- Le paramètre de l'OS repasse en mode clair. Le site reste sombre.
- Les boutons d'activation/désactivation de l'utilisateur. La cible (clair) correspond à la préférence système. La valeur stockée est donc supprimée et le site suit à nouveau le système.
Boutons d'activation/désactivation à trois états
Lorsqu'il y a plus d'espace et que les utilisateurs sont déjà dans l'état d'esprit de définir des préférences à long terme, un contrôle à trois états peut offrir plus de clarté. Dans ce cas, le modèle de données correspond clairement aux trois options d'interface utilisateur : système, clair et sombre.
Pour réduire la charge cognitive, l'option "Système" doit également afficher le paramètre système actuel, par exemple via :
- Icône, par exemple une icône de soleil en bas à droite de l'icône système
- Texte, par exemple "Système (actuellement clair)"