Utilitaires✨ Premium

Theme Toggle

Interrupteur soleil / lune qui bascule vraiment le thème : du cadre de démo à toute la page, réglage de l'appareil et mémoire du choix en option.

CSSToggleTransition

Mis à jour le

Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Utilitaires comprend 43 effets, dont 3 gratuits. Découvrir la catégorie →

3 exemples d'usage

Toute une documentation d'API passe du sombre au clair — Theme Toggle exemple 1

① Toute une documentation d'API passe du sombre au clair

QuandLe développeur lit la page « Créer un paiement » le soir en sombre ; le lendemain, au bureau, il bascule l'interrupteur à droite de la recherche : menu, texte, bloc de code et en-tête passent ensemble au clair.
PourquoiC'est l'usage d'origine d'un interrupteur de thème : il ne colore pas un cadre, il change l'apparence de tout le site. La classe posée sur un seul conteneur suffit, chaque couleur du thème clair étant écrite dans le CSS du site.
Réglagesdata-thm-target="#u737-doc" (le conteneur de la page) ; cadre de démo neutralisé (--thm-height: 0, --thm-page, --thm-panel et --thm-panel-light transparents). Les couleurs claires sont des règles .thm-light de la scène. Dans la capture, la scène appelle root.fx0737.toggle() toutes les 1,3 s.
La terrasse d'un restaurant, de jour ou de nuit — Theme Toggle exemple 2

② La terrasse d'un restaurant, de jour ou de nuit

QuandSur la page de réservation de La Ferlinière, le client hésite pour un dîner en terrasse : l'interrupteur posé sur la photo montre la même terrasse en plein jour, puis le soir avec ses guirlandes allumées.
PourquoiL'icône suit l'action : la lune invite à voir la nuit, le soleil à revenir au jour. Le même composant devient un sélecteur d'aperçu, sans autre code que les deux états de l'illustration.
Réglagesdata-thm-target="#u737-terrace" (le bloc photo seul), aria-label="Vue de jour de la terrasse", interrupteur dans une pastille sombre en haut à gauche. Illustration en CSS dont les couleurs changent sous .thm-light. Bascule automatique toutes les 1,3 s dans la capture.
Trains de jour ou trains de nuit dans un tableau des départs — Theme Toggle exemple 3

③ Trains de jour ou trains de nuit dans un tableau des départs

QuandDans le tableau des départs d'une gare, le voyageur bascule le petit interrupteur de l'en-tête : la liste des trains de nuit (couchettes, voitures-lits) laisse place aux départs du matin, et le tableau passe en clair.
PourquoiIci l'interrupteur filtre une liste : la classe posée sur le tableau affiche l'une ou l'autre des deux listes en plus de changer ses couleurs. Le nom accessible dit ce que fait le bouton (« Trains de jour »), pas « thème ».
Réglagesdata-thm-target="#u737-board", aria-label="Trains de jour" ; dans la scène, .thm-light .u737-day s'affiche et .thm-light .u737-night se masque. Bascule toutes les 1,3 s dans la capture.

Comment ça marche

L'interrupteur est un vrai <button role="switch">. Au clic, à la touche Entrée ou Espace, aria-checked passe de false à true : la pastille glisse vers la droite avec un léger dépassement (cubic-bezier(.68,-.55,.265,1.55), 0,4 s), le soleil tourne et disparaît, la lune apparaît. true veut dire thème clair.

En même temps, le script pose la classe thm-light sur une cible et la retire au retour en sombre. Sans réglage, la cible est le cadre .thm-frame qui entoure l'interrupteur (il passe de #1a1a2e à #f0f0f5). Avec data-thm-target="html" sur la racine, c'est toute la page qui reçoit la classe : vos propres règles html.thm-light { … } font le reste. Le nom de la classe se change avec data-thm-class.

Au chargement, l'état de départ est sombre, sauf si la cible porte déjà la classe (posée par votre serveur, par exemple). data-thm-start="system" lit prefers-color-scheme et suit les changements du réglage de l'appareil tant que le visiteur n'a rien choisi ; data-thm-start="light" démarre en clair. data-thm-storage="theme" enregistre le choix dans localStorage sous cette clé et le reprend à la visite suivante ; sans cet attribut, rien n'est écrit sur l'appareil.

Chaque .fx-0737-root est indépendant ; deux interrupteurs qui visent la même cible (en-tête et pied de page) restent d'accord. Chaque bascule envoie l'événement fx0737:change (detail.light), et root.fx0737.set(true), toggle(), isLight() pilotent l'interrupteur depuis votre code.

Accessibilité

  • Rôle et état : un <button> avec role="switch" et aria-checked ; un lecteur d'écran annonce « Thème clair, interrupteur, activé ». Le nom vient de aria-label, à traduire ou adapter dans le HTML. Le soleil et la lune sont décoratifs (aria-hidden).
  • Clavier : Tab pour l'atteindre, Espace ou Entrée pour basculer ; anneau lavande au focus clavier (:focus-visible). Sur Safari pour Mac, Tab ne s'arrête sur les boutons que si l'option clavier du système est activée (sinon Option + Tab).
  • Contraste : en clair, le rail #e0e0e8 se détache peu du cadre #f0f0f5 ; c'est la pastille indigo qui montre l'état. Sur une page très claire, donnez au rail une bordure plus foncée.
  • Mouvement réduit : sous prefers-reduced-motion: reduce, plus de glissement, de rotation ni de fondu ; l'état change sur place et la bascule du thème fonctionne pareil.

Compatibilité navigateur

Un bouton, du CSS et 3,5 Ko de JavaScript sans dépendance, commentaires compris (classList, CustomEvent, matchMedia, localStorage). Mesuré dans Chromium 151, Firefox 153 et WebKit 26.5 (Playwright) : code collé deux fois dans une page, chaque copie bascule seule, clavier, toucher à 390 px, mouvement réduit, cible html partagée par deux interrupteurs, choix gardé après rechargement, 0 erreur, aucun nom ajouté sur window.

Chrome 86+✓ Complet (mesuré)
Firefox 85+✓ Complet (mesuré)
Safari 15.4+✓ Complet (mesuré dans WebKit)
Edge 86+✓ Complet (moteur Chromium)
Mobile iOS 15.4+✓ Moteur WebKit, non vérifié sur appareil
Android Chrome 86+✓ Complet (toucher mesuré)

Sans JavaScript, le bouton s'affiche mais ne bascule rien. Avant Chrome 86, Firefox 85 et Safari 15.4 (pas de :focus-visible), tout marche mais sans anneau de focus. data-thm-start="system" demande prefers-color-scheme (Chrome 76, Firefox 67, Safari 12.1) ; ailleurs, le départ reste sombre.

Le code

Structure HTML à coller dans votre page (le CSS + JS sont inclus avec votre achat) :

index.html — structure
<div class="fx-0737-root" data-thm-target="html" data-thm-start="system" data-thm-storage="theme">
  <div class="thm-frame">
    <button type="button" class="thm-switch" role="switch" aria-checked="false" aria-label="Thème clair">
      <span class="thm-knob" aria-hidden="true">
        <span class="thm-sun">☀</span>
        <span class="thm-moon">☾</span>
      </span>
    </button>
  </div>
</div>

Paiement unique, sans abonnement — le code est à toi pour toujours

Personnaliser

Options passées à l'API ou attributs data-* :

Option / propriétéDéfautEffet
Cible (HTML — data-thm-target sur la racine) le cadre .thm-frame Sélecteur CSS de l'élément qui reçoit la classe : html pour tout le site, #app pour une zone.
Classe du thème clair (HTML — data-thm-class) thm-light Présente en clair, absente en sombre. Prenez celle que votre CSS utilise déjà (light, is-light…).
Départ (HTML — data-thm-start) dark light démarre en clair ; system lit prefers-color-scheme et suit ses changements jusqu'au premier choix du visiteur.
Mémoire (HTML — data-thm-storage) absent : rien n'est enregistré Clé localStorage (ex. theme) ; la valeur light ou dark est reprise à la visite suivante et passe avant data-thm-start.
Nom lu (HTML — aria-label du bouton) « Thème clair » Dites ce que l'état activé montre : « Vue de jour », « Mode clair »…
Cadre de démo (CSS — --thm-height, --thm-page, --thm-panel, --thm-panel-light, --thm-frame-height) 300 px · #0a0a0f · #1a1a2e · #f0f0f5 · 120 px Mettez 0 et transparent pour poser l'interrupteur seul dans un en-tête.
Pilotage (JS — root.fx0737 et événement fx0737:change) — set(true) force le clair, toggle() inverse, isLight() lit l'état ; l'événement donne detail.light à chaque bascule.

FAQ

Le script tourne après l'affichage du HTML. Ajoutez une ligne dans le <head>, avant vos styles : <script>try{if(localStorage.getItem('theme')==='light')document.documentElement.classList.add('thm-light')}catch(e){}</script>, avec la même clé que data-thm-storage et la cible html.
Dans votre CSS, sous la classe posée sur la cible. Le plus simple : des variables, :root { --fond: #0f1117; --texte: #e5e7eb } puis html.thm-light { --fond: #fff; --texte: #1f2937 }, et partout background: var(--fond).
Oui avec data-thm-start="system", tant qu'il n'a pas touché l'interrupteur et qu'aucun choix n'est mémorisé. Dès qu'il choisit, son choix passe avant le réglage de l'appareil.