Ajouter un mode sombre à un site web (CSS, Tailwind, Next.js)
Ajouter un mode sombre à un site web
Ajouter un mode sombre : CSS, Tailwind et Next.js | We.Inc
Ajoutez un mode sombre avec prefers-color-scheme, des variables CSS et light-dark(), un sélecteur Clair/Sombre/Système, Tailwind v4 et next-themes, sans flash au chargement.
Le mode sombre le plus simple est en CSS pur : déclarez color-scheme: light dark, gardez les couleurs dans des propriétés personnalisées et échangez-les dans @media (prefers-color-scheme: dark). Pour un sélecteur manuel, placez une classe ou un attribut data sur l'élément html, enregistrez le choix dans localStorage et appliquez-le avec un tout petit script en ligne dans le head pour que le mauvais thème ne s'affiche jamais, même un instant.
Quelle approche convient à votre stack
Stack
Suit le système
Sélecteur manuel
Élément clé
CSS pur
Oui
Non
@media (prefers-color-scheme: dark)
CSS + petit script
Oui
Oui
data-theme sur html + script en ligne dans le head
Tailwind CSS v4
Oui, par défaut
Avec @custom-variant
utilitaires dark:
Next.js App Router
Oui
Oui
ThemeProvider de next-themes
Le mode sombre repose sur trois éléments : des couleurs qui peuvent basculer, un moyen de décider quel jeu utiliser, et un bon timing pour que la page s'affiche correctement dès le premier rendu. L'aperçu ci-dessous vous permet de passer entre clair, sombre et système sur une mise en page d'exemple, puis chaque section donne le code exact pour CSS pur, Tailwind et Next.js.
Choisissez Clair, Sombre ou Système dans l'aperçu. Système suit votre système d'exploitation et se met à jour en direct si vous le changez.
Remarquez que le champ de formulaire et la barre de défilement basculent aussi. C'est l'effet de la propriété color-scheme.
Choisissez votre stack dans les exemples ci-dessous et copiez le code. Le script anti-flash se place en ligne dans le head.
Testez en rechargeant dans chaque mode, puis une fois avec votre système en sombre et aucune préférence enregistrée.
N'inversez pas simplement du noir pur sur du blanc pur. Des gris foncés légèrement éclaircis avec un texte blanc cassé sont plus agréables à lire longtemps.
Vérifiez à nouveau le contraste dans les deux thèmes. Un bleu de marque conforme sur blanc peut échouer sur un fond gris foncé.
Prévoyez une variante sombre des images et logos, ou un fond transparent, pour qu'une boîte blanche ne brille pas sur une page sombre.
Représentez le mode système par l'absence de valeur enregistrée plutôt que par un mot, pour qu'un changement ultérieur du système soit toujours suivi.
Ajoutez <meta name="color-scheme" content="light dark"> pour que le navigateur affiche un fond sombre avant l'arrivée de votre CSS.
Questions fréquentes
Comment éviter le flash blanc au chargement de la page en mode sombre ?
Décidez du thème avant le premier rendu. Placez un petit script bloquant en haut du head qui lit le choix enregistré et la préférence système, puis définit la classe ou l'attribut sur l'élément html. Les scripts en fin de body ou dans un composant de framework s'exécutent trop tard.
Comment fonctionne le mode sombre de Tailwind ?
Dans Tailwind v4, la variante dark: utilise prefers-color-scheme par défaut, donc dark:bg-gray-900 s'applique quand le système est en sombre. Pour la piloter avec un sélecteur, ajoutez @custom-variant dark (&:where(.dark, .dark *)); à votre CSS et placez la classe dark sur l'élément html.
Comment ajouter un mode sombre dans Next.js ?
La voie courante est le package next-themes, sous licence MIT. Enveloppez l'application dans son ThemeProvider dans le layout racine, ajoutez suppressHydrationWarning à la balise html et appelez setTheme depuis useTheme dans un composant client. Il injecte le script anti-flash pour vous.
À quoi sert color-scheme ?
Il indique au navigateur quels schémas votre page prend en charge, pour que les parties natives comme les contrôles de formulaire, les barres de défilement et le fond de page utilisent des couleurs adaptées. Définir color-scheme: light dark sur la racine est aussi nécessaire pour que la fonction light-dark() choisisse sa seconde valeur.
Le mode sombre doit-il suivre le système ou avoir un sélecteur ?
Les deux. Utilisez par défaut la préférence système, puisque les gens l'ont déjà choisie, et proposez un sélecteur Clair, Sombre et Système pour qu'un visiteur puisse la remplacer sur votre site uniquement.
Construisez d'abord la palette avec des variables
Nommez les couleurs selon leur rôle, pas leur apparence : --bg, --surface, --text, --muted, --accent, --border. Les composants n'utilisent jamais que ces noms. Changer de thème revient alors à redéfinir une poignée de variables à un seul endroit.
La fonction light-dark() raccourcit encore cela en contenant les deux valeurs dans une seule déclaration. MDN l'indique comme Baseline 2024 : gardez donc une solution de repli pour les navigateurs plus anciens si votre audience en a besoin.
Rendre le sélecteur accessible
Un sélecteur est un vrai bouton avec un nom clair. Pour un interrupteur à deux états, utilisez aria-pressed ; pour trois choix, un petit groupe de boutons radio ou un select est plus clair qu'une icône qui tourne en boucle.
N'annoncez rien de plus. Le changement visible est le retour, et l'état propre du contrôle indique aux utilisateurs de lecteurs d'écran ce qui est sélectionné.
Rendu serveur et hydratation
Un serveur ne peut pas connaître le thème d'un visiteur à la première requête, le HTML rendu ne peut donc pas contenir de texte propre à un thème comme Passer en clair. N'affichez le libellé du sélecteur qu'après le montage du composant, ou affichez quelque chose de neutre.
C'est aussi pour cela que next-themes demande suppressHydrationWarning sur html : son script modifie un attribut à cet endroit avant que React n'hydrate.
1. CSS pur qui suit le système
Variables échangées par prefers-color-scheme
Le cadre de résultat suit le réglage de votre appareil. Passez votre système en sombre et il se met à jour sans rechargement.
La même idée avec light-dark()
Une déclaration par couleur. Il faut color-scheme sur la racine, et MDN l'indique comme Baseline 2024.
2. Un sélecteur Clair, Sombre et Système sans flash
Script en ligne en haut du head
S'exécute avant l'affichage du body. Sans valeur enregistrée, il ne fait rien, et la media query continue de suivre le système.
Un CSS qui respecte à la fois l'attribut et le système
L'attribut l'emporte quand il est présent. Sinon, c'est la media query qui décide.
Le sélecteur lui-même
Un select à trois options. Choisir Système supprime la valeur enregistrée.
3. Tailwind CSS v4
Utilitaires dark: avec une classe à basculer
Sans la ligne @custom-variant, dark: suit prefers-color-scheme. Avec elle, la classe dark sur html contrôle le thème.
4. Next.js App Router avec next-themes
Layout racine et provider client
ThemeProvider est un composant client, il vit donc dans son propre fichier. attribute="class" l'associe à la classe dark de Tailwind.
Un sélecteur qui attend d'être monté
Le serveur ne connaît pas le thème, le contrôle s'affiche donc après le montage pour éviter un écart d'hydratation.
Aperçu du thème
Passez entre Clair, Sombre et Système pour voir une mise en page d'exemple changer, y compris ses contrôles de formulaire.
Thème
Clair
Sombre
Système (sombre actuellement)
Système (clair actuellement)
Boulangerie du Port
Exemple
Menu
Nous trouver
Tout frais à 7h
Pains au levain, de seigle et aux graines chaque matin.