Blog des Gens Compliqués

Bouton à bascule en HTML/CSS

28/11/2025 15:00:18+01:00|Par DkVZ
4 minutes de lecture (facile)

Mes articles de web design sont les moins populaires du blog. Je suis même pas vraiment un vrai designer.

Alors pourquoi je m'obstine à publier mes articles CSS Tricks de Wish?

Ben je sais pas, peut-être que mon oeuvre la plus glorieuse de ces dernières semaines c'est un BOUTON A BASCULE. Peut-être est-ce la raison. Peut-être.

Je suis même pas sûr que quelqu'un ait déjà appelé ça un "bouton à bascule" depuis le Big Bang mais c'est trop tard maintenant.

Et alors, aussi, y a des boutons à bascule subtilisables partout sur le net, dont plusieurs vraiment dingo ici, par exemple.

Je vous ai déjà parlé de mon futur nouveau blog? Oui? J'en parle non-stop depuis 6 mois? Peut-être.

Sur le blog version "pas de framework" j'ai utilisé Materialize, un framework CSS (oui il y en avait tout un tas il y a 10 ans) dont le dernier commit date d'il y a 5 ans et est probablement un "UPDATE README".

Ils proposent un bouton à bascule que vous pouvez voir sur mes pages de liste d'articles:

Montre le bouton qui permet de basculer ordre décroissant ou croissant sur mes pages de liste d'article
Mooh quel beau bouton à bascule dis!

Etant donné que j'écris tous les styles moi-même comme un grand malade sur le nouveau blog plutôt qu'utiliser Tailwind comme tout le monde, je me suis dit... Je vais créer ce bouton en partant de 0.

Je vois même comme le rendre opérationnel sans JavaScript en utilisant la bonne vieille astuce du checkbox et du sélecteur de voisin. Le quoi? Euh non rien, c'est pas important.

Presque sans rapport, je me suis souvenu d'une expérience d'animation de bouton réalisée sur Codepen, probablement depuis mes cabinets.

Il s'agit juste de scale à outrance avec une transition (le bouton du bas n'a rien à voir lol):

Je me suis dit, pourquoi pas avoir deux "boutons" tellement proches qu'on dirait qu'ils font partie du même contrôle avec la bascule représentée par cette mise à l'échelle? Et aussi un petit changement de l'ombre portée peut-être pour montrer la profondeur? Peut-être?

Regardons d'abord une proposition de HTML, ici avec des options textuelles "Croissant" et "Décroissant" comme sur les pages de liste d'articles (sauf que j'ai inversé quelle option est par défaut et j'ai la flemme de changer):

<input id="toggle-checkbox-1" name="toggle-checkbox-1" class="toggle-checkbox" type="checkbox" />
<label class="toggle-label" for="toggle-checkbox-1" aria-label="Toggle the option">
  <div class="toggle-indicator flex-center">
    Croissant
  </div>
  <div class="toggle-indicator flex-center">
    Décroissant
  </div>
</label>

Remarquez que l'élément input est juste à côté du label, qui est bien marqué comme correspondant au dit input.

Le label devient alors focusable et cliquable (je parle FRNASIAS) même si le checkbox est invisible.

Comme on est sur des contrôles natifs, la barre d'espace fonctionne aussi naturellement pour activer la bascule sans aucun JavaScript supplémentaire.

Du coup voici le CSS qui n'est probablement pas optimal:

:root {
  --light-gray-color: #333;
  --light-color: rgb(243, 234, 211);
  --grayed-color: rgb(251, 241, 199);
}

.toggle-checkbox {
  opacity: 0;
  width: 0;
  height: 0;
  position: absolute;
}

.toggle-label {
  display: flex;
  gap: 0.15rem;
}

.toggle-indicator {
  transition: all 0.28s cubic-bezier(0.4, 0, 0.2, 1);
  padding: 0.4rem;
  font-size: 1rem;
  border-radius: 5px;
  background-color: var(--light-gray-color);
  color: var(--light-color);
  border: 1px solid var(--grayed-color);
  box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14),
    0 1px 18px 0 rgba(0, 0, 0, 0.12),
    0 3px 5px -1px rgba(0, 0, 0, 0.4);
}

.toggle-label .toggle-indicator:nth-child(1) {
  font-weight: 600;
  transform: scale(1.2);
  box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14),
    0 1px 18px 0 rgba(0, 0, 0, 0.12),
    0 3px 5px -1px rgba(0, 0, 0, 0.4);
}

.toggle-checkbox:checked+label .toggle-indicator:nth-child(2) {
  font-weight: 600;
  transform: scale(1.2);
  box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14),
    0 1px 18px 0 rgba(0, 0, 0, 0.12),
    0 3px 5px -1px rgba(0, 0, 0, 0.4);
}

.toggle-checkbox:checked+label .toggle-indicator:nth-child(1) {
  font-weight: initial;
  transform: initial;
}

On a donc:

  • Le checkbox avec opacité 0 et une hauteur et largeur de 0 ;
  • Les "indicateurs" (c'étaient des boutons dans mon codepen, ici c'est des div) qui sont stylés selon que le checkbox soit checked ou pas avec les sélecteurs de folie à base de "+" et "nth-child".

Me demandez pas quelle est la différence entre le sélecteur ~ et le + parce que je sais toujours pas.

Dans l'état initial c'est l'indicateur de gauche qui prend le dessus.

Evidemment (bah ouais) j'ai un composant pour ça dans mon projet Nuxt. Je vous ai quand même pondu UNE BONNE VIEILLE PAGE DE DEMO parce que je sais que vous adorez-ça.

Festoyez vos orbites plein d'yeux sur mes talents web que jamais une IA vous pondera un truc pareil:

Allez, joyeux Noël les cocos

Commentaires

Il faut JavaScript activé pour écrire des commentaires ici

Ajouter un commentaire

Votre commentaire a été ajouté
(enfin, je pense)