Intégrer un button de choix du thème graphique, c’est bien ; proposer un menu de sélection du thème permettant de synchroniser à tout moment avec le thème système, c’est mieux !
J’aime beaucoup la façon dont le site MDN Web Docs de Mozilla a pensé et implémenté la fonctionnalité de sélection du thème graphique. Tant et si bien que j’ai décidé de le reproduire au sein de mon site.
Peu après l’avoir publié, je suis tombé sur des ressources en ligne et j’ai eu des retours de personnes soulevant des limites / défauts métier, au mécanisme que j’avais mis en place.
Proposer un thème light et un thème dark, à la convenance de l’utilisateur, est devenu une fonctionnalité basique.
De plus en plus, les sites offrent une troisième option à leurs visiteurs consistant à synchroniser le thème automatiquement avec le thème système.
J’ai bien pris en compte cette fonctionnalité dans mon article.
Cependant, d’un point de vue ergonomie, la solution retenue - un bouton switch, avec un comportement par défaut s’il n’a “jamais” été cliqué - présente plusieurs défauts :
elle est irréversible
sauf à aller vider manuellement le Local Storage (bon courage sous iPhone ou Android)
sans que l’utilisateur en ait conscience ou ne puisse faire quelque chose
Par ailleurs, en termes d’accessibilité, là aussi j’ai fait des efforts et la solution proposée est satisfaisante, mais il y des soucis au niveau du rendu graphique en cas de focus (absence de bordure) et l’utilisation des aria-* n’étaient pas dingue.
Bref, c’était très loin d’être optimal et j’ai décidé de revoir ma copie.
Exemples
Dans les retours importants qui m’ont été faits (merci à tous pour les feedbacks 🙏), j’ai notamment eu celui de Vincent (a.k.a. “La Relève”) qui m’a pointé l’exemple de Mozilla et son site MDN Web Docs.
Au moment où j’écris ces lignes, le menu de sélection du thème de mon site est “très fortement inspiré” du leur.
(*) en vrai, j’ai quasi tout pompé, jusqu’à la structure HTML et la gestion de l’accessibilité 😬
MDN Web Docs :
Ci-dessous, je vous partage des captures de plusieurs autres sites qui proposent eux-aussi une gestion moderne de choix du thème de couleurs.
GitHub :
StackOverflow :
Même un projet de plus petite envergure comme Plausible propose un menu de sélection du thème proposant le choix système plutôt qu’un simple bouton toggle.
Plausible :
Conception
En termes d’attentes, l’objectif est d’avoir exactement le même comportement que le site de Mozilla :
Visuel
un élément interactif pour ouvrir le menu des thèmes
en l’occurrence, un simple bouton
situé dans la barre d’en-tête du site sur toutes les pages, en lieu et place du bouton à bascule initial
une signalétique / des éléments pour visualiser en un coup le thème actuel
une icône dans la barre d’en-tête correspondant au thème sélectionné, associé au bouton déroulant
un style particulier pour l’option de thème actuel, dans le menu déroulant
un menu déroulant avec les 3 options possibles :
“os-default”, pour synchroniser le thème du site avec les préférences utilisateurs
“light”, pour forcer le mode clair
“dark”, pour forcer le mode sombre
une icône spécifique pour chaque option (reprise dans l’icône de la barre d’en-tête du site, cf. ci-dessus)
Comportements
quand on clique sur le “bouton de sélection du thème”, alors
le menu déroulant (menu popup) apparaît,
présentant les 3 options de thème
avec une visualisation particulière pour le thème actuel
quand on sélectionne une option :
dans tous les cas le menu se ferme et l’icône dans la barre d’en-tête est mise à jour, par rapport au thème sélectionné
si le thème sélectionné est celui actuel, rien d’autre ne se passe
sinon, l’icône du menu principal change et lorsque l’on ouvre à nouveau le menu déroulant, l’item sélectionné est bien celui précédemment sélectionné
lorsque le menu déroulant est ouvert, il est possible de le fermer sans effet :
en cliquant en dehors du menu
en appuyant sur la touche d’échappement
Autres
par défaut, le thème sélectionné est celui des préférences système
lorsque l’utilisateur revient sur le site, ses préférences de navigation sont restaurées / chargées
le menu doit être accessible :
il doit être possible de naviguer, ouvrir et fermer le menu au clavier
les outils de lecture d’écran doivent fonctionner correctement
le menu doit satisfaire aux exigences de WAVE + LightHouse
ce type de composant ne doit pas dégrader les performances du site
Réalisation
Général
Je prends le parti d’avoir une solution la plus générique et agnostique possible.
Intention ou idée : pouvoir simplement componentiser (dans un Web Component) le résultat final.
Ainsi, tous les event listeners / handlers seront déclarés directement dans un fichier JS dédié : theme-switcher-menu.js (dans le répertoire des assets).
Proposer un menu déroulant (plutôt qu’un bouton à bascule)
De base, au chargement de la page, le menu déroulant est déclaré dans le HTML/DOM, mais caché (via la classe .hidden).
Celui-ci est matérialisé sous la forme d’une liste non ordonnée (élément <ul>) avec des boutons.
🤔 J’ai repris la structure proposée par Mozilla. J’avoue que je m’attendais plutôt à un élément <select>.
L’ouverture du menu passe par un élément de type <button>.
On précise l’attribut type="button" pour éviter l’envoi éventuel de formulaire et s’épargner une instruction event.preventDefault() dans le code.
On branche un écouteur sur l’évènement click du bouton.
si le menu - <ul.theme-switcher-menu__list> - est caché (possède la classe .hidden), alors on l’affiche (on supprime la classe)
sinon, on le ferme (ajout de la classe sur l’élément <ul>)
ℹ️ L’implémentation est un peu différente ici de ce que fait Mozilla, qui utilise React et donc passe par les mécaniques liées au Shadow DOM.
Tenir compte du thème sélectionné
À la différence du bouton à bascule simple, détecter l’option choisie par l’utilisateur nécessite de passer par un moyen quelconque.
J’ai opté pour un attribut de donnée data-theme-option dont la valeur dépende de l’option.
À l’initialisation de la page / exécution du script, l’idée consiste à associer un event handler pour chaque évènement click des 3 boutons-options possible.
ℹ️ Je ne rentre pas ici dans le détail de la gestion des préférences système utilisateur via la Media Query window.matchMedia("(prefers-color-scheme: dark)") ou de la persistance du choix cross-visites via le Local Storage. Tout est dans l’article précédent.
Tenir compte de la navigation au clavier
L’élément qui affiche / cache le menu déroulant, ainsi que les 3 options du menu sont tous des boutons.
De fait, en tant que boutons