Skip to Content
BootstrapPartie 9 — Color modes & dark mode9.3 — Piloter le mode en JavaScript

9.3 — Piloter le mode en JavaScript

⏱️ TL;DR — Un sélecteur de thème = changer data-bs-theme sur <html> en JS, le persister (localStorage) et respecter la préférence système (prefers-color-scheme). Pour éviter le flash au chargement (SSR), appliquez le thème via un petit script inline dans le <head>, avant le rendu.

🎯 Objectifs

  • Basculer le thème en JS.
  • Persister le choix et suivre la préférence système.
  • Éviter le flash clair→sombre.

Basculer et persister

<button id="toggle" class="btn btn-outline-secondary">🌓 Thème</button>
const html = document.documentElement function setTheme(theme) { html.setAttribute('data-bs-theme', theme) localStorage.setItem('theme', theme) } document.getElementById('toggle').addEventListener('click', () => { const current = html.getAttribute('data-bs-theme') setTheme(current === 'dark' ? 'light' : 'dark') })

Choix initial : stocké > système > clair

function preferredTheme() { const stored = localStorage.getItem('theme') if (stored) return stored return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } setTheme(preferredTheme())

Suivre la préférence système en direct

window.matchMedia('(prefers-color-scheme: dark)') .addEventListener('change', e => { if (!localStorage.getItem('theme')) { // seulement si l'utilisateur n'a pas choisi setTheme(e.matches ? 'dark' : 'light') } })

Éviter le flash (FOUC de thème)

Le problème : la page se peint en clair, puis le JS passe en sombre → un flash. Solution : un script bloquant et inline tout en haut du <head>, exécuté avant le premier rendu :

<head> <script> (function () { var t = localStorage.getItem('theme') || (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') document.documentElement.setAttribute('data-bs-theme', t) })() </script> <!-- puis le CSS --> </head>

⚠️ Piège — Mettre ce script en bas de page ou en defer : trop tard, le flash a lieu. Il doit être synchrone, dans le <head>, avant le contenu.

💡 Pour un dev React / Next.js — Ne réinventez pas la roue : next-themes gère toute cette logique (persistance, système, anti-flash via un script injecté) et fonctionne avec data-bs-theme en passant attribute="data-bs-theme". C’est la solution recommandée en App Router. Voir Partie 11.

✏️ Exercices

  1. Écrire la fonction qui choisit le thème initial (stocké, sinon système).

✅ Solution

Voir preferredTheme() ci-dessus : localStorage.getItem('theme') puis matchMedia('(prefers-color-scheme: dark)').

  1. Pourquoi le script anti-flash doit-il être inline et synchrone dans le <head> ?

✅ Solution

Pour appliquer le thème avant le premier rendu ; sinon la page s’affiche en clair puis « saute » en sombre.

🧠 Quiz de révision

1. Comment changer le thème en JS ?

document.documentElement.setAttribute('data-bs-theme', …).

2. Comment persister le choix ?

localStorage.

3. Quelle media query donne la préférence système ?

prefers-color-scheme: dark.

4. Comment éviter le flash de thème ?

Un script inline synchrone dans le <head>, avant le rendu.

5. Quelle lib gère tout ça en Next.js ?

next-themes (avec attribute="data-bs-theme").


🎉 Fin de la Partie 9 ! Partie suivante : Partie 10 — Le JavaScript de Bootstrap