10 points par GN⁺ 2026-04-20 | 1 commentaires | Partager sur WhatsApp
  • De la fonctionnalité native du navigateur aux media queries JavaScript, voici une synthèse en 8 niveaux qui élargissent progressivement le champ d’implémentation du mode sombre
  • L’approche la plus simple consiste à déclarer <meta name="color-scheme" content="light dark"> ou color-scheme: light dark pour suivre la préférence de schéma de couleurs de l’utilisateur
  • À des niveaux plus avancés, la fonction light-dark(), @media (prefers-color-scheme: dark) et des feuilles de style séparées par schéma permettent d’ajuster largement non seulement les couleurs, mais aussi les images et les ombres
  • Il est possible de créer un sélecteur proposant Automatic·light·dark au lieu de simplement suivre les réglages système, et de déterminer le thème à partir de :has() et du véritable élément meta
  • L’article couvre aussi les limites d’accessibilité de Safari et le comportement observé de prefers-color-scheme à l’impression, montrant qu’avec les fonctionnalités CSS récentes, intégrer un mode clair/sombre est devenu plus facile

Implémentation du mode sombre par niveaux

  • Niveau 1 : Minimal

    • Il est possible d’activer la distinction clair/sombre sans une seule ligne de CSS, simplement en ajoutant <meta name="color-scheme" content="light dark"> dans le head du document, ce qui fait que le navigateur commence à suivre la préférence de schéma de couleurs de l’utilisateur
    • L’ordre des éléments dans l’attribut content a théoriquement un sens : pour les utilisateurs qui n’ont pas indiqué de préférence de schéma de couleurs, la première valeur de la liste séparée par des espaces est appliquée
    • Les systèmes d’exploitation actuels ne proposent pas d’option « sans choix de schéma de couleurs », donc en pratique le résultat correspond au schéma défini dans l’OS
    • On peut aussi ne fournir qu’une seule valeur dans content, auquel cas ce schéma est imposé sans tenir compte de la préférence utilisateur
    • Cette balise meta joue dans une certaine mesure le rôle d’une approche côté HTML correspondant à la méthode CSS du niveau suivant
  • Niveau 2 : Basique

    • En CSS, on peut activer la distinction mode clair / mode sombre avec la déclaration html { color-scheme: light dark; }
    • Si la balise meta est déjà présente dans le DOM, cette déclaration n’est pas nécessaire ; si l’on contrôle le HTML, il est recommandé d’utiliser la balise meta, car le navigateur connaît l’instruction avant même de parser le CSS
    • Les deux approches permettent de tirer parti des styles par défaut du user agent et du mode clair/sombre qu’ils incluent
    • En ajoutant ensuite du CSS tout en se limitant principalement aux CSS system colors, on peut obtenir un design déjà assez propre
    • Contrairement à la balise meta, qui s’applique toujours à l’ensemble du document, la déclaration CSS color-scheme peut aussi être définie ailleurs que sur l’élément racine, ce qui ouvre des usages supplémentaires
  • Niveau 3 : Mesuré

    • La fonction de couleur CSS light-dark(), ajoutée relativement récemment, permet d’effectuer des ajustements simples pour le mode clair/sombre
    • Dans l’exemple, elle est utilisée comme background-color: light-dark(black, white); et color: light-dark(white, black); ; le premier argument s’applique au mode clair et le second au mode sombre
    • Les arguments peuvent être des couleurs explicites, mais aussi des custom properties interprétables comme couleurs
    • Dans tout l’article, c’est le seul niveau dont la prise en charge navigateur reste insuffisante au moment de l’écriture
  • Niveau 4 : Franc

    • Le basculement vers le mode sombre peut être implémenté avec la media query classique @media (prefers-color-scheme: dark)
    • Que l’on interroge light ou dark, cela permet le niveau maximal de personnalisation, bien au-delà d’un simple changement de couleurs
    • On peut par exemple désaturer des images avec des filtres en mode sombre, ou remplacer les ombres portées par des contours
  • Niveau 5 : Bisectionnel

    • Les media queries peuvent aussi être utilisées en HTML, via l’attribut media d’un élément link, afin de séparer les feuilles de style par schéma
    • L’exemple relie light.css à prefers-color-scheme: light et dark.css à prefers-color-scheme: dark
    • Quand le niveau de personnalisation est important, une organisation en fichiers dédiés est adaptée, et le navigateur peut ignorer le fichier CSS qui ne correspond pas à la requête, ce qui peut réduire d’un fichier le téléchargement nécessaire
  • Niveau 6 : Balistique

    • En JavaScript, on peut utiliser la media query de schéma de couleurs via window.matchMedia('(prefers-color-scheme:dark)')
    • Comme avec les autres media queries, on peut interroger le schéma clair ou sombre puis effectuer le traitement souhaité en fonction du résultat
    • Dans une implémentation réelle, il n’est pas nécessaire de s’en tenir à une seule technique parmi les niveaux précédents : on peut les combiner

Sélecteur utilisateur et motifs avancés

  • Niveau 7 : Au-delà

    • Il n’est pas nécessaire de dépendre uniquement des préférences système de l’utilisateur : on peut construire un sélecteur de schéma de couleurs
    • Ce sélecteur n’est pas un simple booléen ; il doit inclure un mode Automatic qui suit prefers-color-scheme comme valeur par défaut initiale
    • Une fois ce sélecteur ajouté, l’utilisateur peut choisir entre les trois modes Automatic, light et dark
  • Niveau 8 : Astucieux

    • Pour implémenter le sélecteur du niveau 7, on ajoute souvent une classe .dark ou un attribut comme data-theme="dark" à un élément HTML
    • À la place, on peut utiliser :has() pour interroger directement la présence réelle de <meta name="color-scheme" content="dark">
    • Dans l’exemple, sous le sélecteur html:has(meta[name="color-scheme"][content="dark"]), des variables CSS comme --color-bg et --color-text reçoivent leurs valeurs du mode sombre
    • Il est donc possible de déterminer le thème à partir du véritable élément meta, sans classe ni attribut de données supplémentaire

Discussions et observations complémentaires

  • Observation lors du CSS Naked Day

    • Après suppression des styles, l’absence de mode sombre est apparue de façon flagrante sur presque tous les sites visités, ce qui a mené à cette classification par niveaux
    • Il est également mentionné que, lorsqu’on construit un nouveau site à partir de zéro avec de nouveaux styles, les fonctionnalités CSS récentes rendent l’intégration native du mode clair/sombre très facile
  • Problèmes d’accessibilité dans Safari

    • L’article souligne que, jusqu’à une date assez récente, Safari ne fournissait pas de couleurs de lien accessibles en mode sombre
    • Il mentionne aussi qu’au cours d’un précédent CSS Naked Day, ce problème avait conduit à retirer la balise meta et à n’utiliser qu’un schéma clair
    • La balise meta a ensuite été réintroduite, tout en gardant à l’esprit qu’une dégradation de l’accessibilité peut subsister pour les utilisateurs d’anciennes versions de Safari
    • Il est également constaté que, dans le mode sombre de Safari, les champs de texte n’ont pas de bordure visible
    • Comme les styles du user agent ne suffisent pas à garantir une accessibilité complète, même avec un HTML sémantiquement correct, l’auteur réfléchit à conserver suffisamment de styles lors des prochains CSS Naked Day
  • Impression et condition screen and

    • Dans l’exemple Bisectionnel, l’usage de screen and ... est expliqué par la volonté d’exclure les imprimantes
    • En partant de l’hypothèse qu’il existe une feuille de style principale indépendante du thème ou une feuille dédiée à l’impression, l’idée est de séparer cela par prudence, car le mode sombre pourrait consommer davantage d’encre à l’impression
    • Lors des tests réels, même avec le mode sombre activé au niveau système, l’impression produisait seulement du texte noir sur papier blanc, ce qui a conduit à observer que les navigateurs n’appliquent pas ces styles de mode sombre à l’impression
    • Dans des tests supplémentaires, l’aperçu avant impression signalait toujours prefers-color-scheme comme light, ce qui a été vérifié dans Firefox et Chromium
    • L’article conclut sur une remarque humoristique regrettant l’absence d’imprimantes utilisant du papier noir et de l’encre blanche

1 commentaires

 
GN⁺ 2026-04-20
Réactions sur Hacker News
  • Si on fait beaucoup de personnalisation, un fichier dédié se défend, mais l’explication selon laquelle le CSS non conforme aux media queries ne serait même pas téléchargé ne correspond pas, à mon avis, au fonctionnement réel des navigateurs. D’après mon expérience, le navigateur télécharge tout au final, en changeant seulement la priorité
  • Je me demandais s’il n’existait toujours aucun moyen d’éviter ce scintillement façon flashbang qui survient pendant qu’on attend le contenu initial côté serveur
    • Je trouve que définir background-color dans le userContent.css de Firefox est une solution correcte
    • Moi, j’ai simplement baissé la luminosité de l’écran et désactivé le mode sombre, et le flashbang a disparu. En prime, la batterie tient plus longtemps
  • Je pensais que cet article parlerait des préférences sur le niveau de noir du fond en mode sombre. J’ai aussi entendu dire que le noir pur est meilleur pour l’autonomie sur OLED, et je connais des gens qui préfèrent un gris moins absolu qu’un noir parfait. Cela dit, je ne suis pas sûr qu’il faille vraiment six niveaux, et j’ai l’impression qu’on perçoit au plus 3 ou 4 niveaux
    • Je pensais qu’une solution plus générale serait la normalisation de la compatibilité avec le Reader Mode. Au lieu d’un problème en n x m où chaque site doit s’adapter à toutes les préférences de tous les utilisateurs, il vaudrait mieux que les sites prennent en charge une seule vue de contenu simple et que le navigateur gère ensuite les réglages propres à chaque utilisateur
    • Sur OLED, j’ai plutôt tendance à préférer le noir pur. J’ai l’impression que moins les pixels s’allument, moins il y a de risque de burn-in, et comme la durée de vie est de toute façon limitée, je préfère pouvoir garder un écran plus de 5 ans plutôt que seulement 2 ou 3 ans
  • Pour moi, le meilleur niveau, c’est 9 — ou 0 —, c’est-à-dire éteindre l’ordinateur et aller dormir
  • J’ai été content de voir que l’OP avait bien implémenté un toggle à 3 états
  • J’aurais trouvé ça plus amusant si les niveaux s’étaient appliqués dynamiquement au fil du défilement
    • Ou alors, j’aurais aussi trouvé ça bien que le lecteur puisse choisir le niveau lui-même à différents endroits pertinents de la page
  • À mon avis, ça fait plutôt 8 niveaux, non ?
  • Ça donnait vraiment une impression de 2024
  • Dans ce contexte, ça m’a immédiatement fait penser à xkcd 3227