Bouton à bascule (Switch)
Un interrupteur permettant d'activer ou désactiver une option de manière binaire (On/Off), sans JavaScript.
1. Démonstration
2. Accessibilité (La magie du role="switch")
Créer un interrupteur accessible sans JavaScript est possible en détournant intelligemment une case à cocher native.
| Concept / Attribut | Explication |
|---|---|
<input type="checkbox"> |
Fournit nativement la gestion du focus clavier (Tab) et le changement d'état via la touche Espace. |
role="switch" |
Modifie la sémantique de la case à cocher. Au lieu de dire "coché/non coché", le lecteur d'écran annoncera "activé/désactivé" (ou On/Off), ce qui correspond à l'attente cognitive d'un interrupteur. |
| Zone de clic étendue | Envelopper l'<input> et le texte dans une balise <label> permet à l'utilisateur de cliquer sur le texte pour actionner le switch. |
Note RGAA : Si l'action du switch modifie immédiatement l'interface (comme le changement de thème clair/sombre), il est parfois préférable d'utiliser un <button aria-pressed="true/false"> couplé à du JavaScript. Mais pour des réglages de formulaire, le <input type="checkbox" role="switch"> est parfait !
3. Code source
HTML
La structure est identique à celle d'une case à cocher classique, avec le role="switch" en plus.
<label class="switch-label">
<input type="checkbox" role="switch" name="newsletter">
Abonnement à la newsletter
</label>
CSS
Ce code utilise appearance: none pour effacer le rendu natif du navigateur. Il dessine ensuite le fond de l'interrupteur, et utilise le pseudo-élément ::before pour créer la pastille (le curseur) qui se déplace avec une transition fluide.
/* Style du conteneur (Label) */
.switch-label {
display: inline-flex;
align-items: center;
gap: 1rem;
cursor: pointer;
font-weight: 700;
width: fit-content;
}
/* La piste de l'interrupteur (Background) */
input[type="checkbox"][role="switch"] {
-webkit-appearance: none;
appearance: none;
background-color: transparent;
margin: 0;
width: 3rem; /* Largeur de la pilule */
height: 1.5rem; /* Hauteur de la pilule */
border: 2px solid var(--border-color);
border-radius: 1.5rem; /* Forme de pilule */
position: relative;
cursor: pointer;
transition: background-color var(--transition-speed) ease;
}
/* Focus visible très contrasté */
input[type="checkbox"][role="switch"]:focus-visible {
outline: 3px solid var(--text-color);
outline-offset: 3px;
}
/* La pastille de l'interrupteur (Le fond rond) */
input[type="checkbox"][role="switch"]::before {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: calc(1.5rem - 8px);
height: calc(1.5rem - 8px);
border-radius: 50%;
background-color: var(--text-color);
transition: transform var(--transition-speed) ease-in-out, background-color var(--transition-speed) ease;
}
/* L'icône interne (Croix ou Coche via clip-path) */
input[type="checkbox"][role="switch"]::after {
content: "";
position: absolute;
/* On centre parfaitement l'icône de 8px au milieu de la pastille de 16px */
top: 6px;
left: 6px;
width: calc(1.5rem - 16px);
height: calc(1.5rem - 16px);
background-color: var(--bg-color); /* L'icône prend la couleur de fond (noir) */
/* Forme de la Croix (X) */
clip-path: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%);
transition: transform var(--transition-speed) ease-in-out, background-color var(--transition-speed) ease;
}
/* États : Coché / Activé */
input[type="checkbox"][role="switch"]:checked {
background-color: var(--text-color);
}
input[type="checkbox"][role="switch"]:checked::before {
/* On déplace la pastille vers la droite */
transform: translateX(1.5rem);
background-color: var(--bg-color);
}
input[type="checkbox"][role="switch"]:checked::after {
/* On déplace l'icône en synchronisation avec la pastille */
transform: translateX(1.5rem);
background-color: var(--text-color);
/* La Croix se transforme instantanément en Coche (✓) */
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
}