Case à cocher

Éléments de formulaire permettant la sélection d'une ou plusieurs options, personnalisés en pur CSS.

1. Démonstration

Quelles technologies utilisez-vous ? (Choix multiples)
Quel est votre thème préféré ? (Choix unique)

2. Accessibilité (Sémantique et Clavier)

Utiliser les éléments natifs permet aux lecteurs d'écran et à la navigation au clavier de fonctionner parfaitement sans aucun JavaScript.

Élément / Interaction Explication
<fieldset> et <legend> Crucial : Regroupe les options entre elles. Le <legend> agit comme la « question » globale et est annoncé par le lecteur d'écran avant chaque option.
<label> englobant Envelopper l'<input> dans le <label> augmente la zone cliquable (on peut cliquer sur le texte) et associe implicitement le texte à la case.
  • L’étiquette est visuellement accolée immédiatement au-dessous ou à droite du champ de formulaire lorsque le sens de lecture de la langue de l’étiquette est de gauche à droite ;
  • L’étiquette est visuellement accolée immédiatement au-dessous ou à gauche du champ de formulaire lorsque le sens de lecture de la langue de l’étiquette est de droite à gauche.
Cases à cocher (Clavier) On utilise la touche Espace pour cocher/décocher. On navigue de l'une à l'autre avec Tab.
Boutons radio (Clavier) On navigue à l'intérieur du groupe avec les Flèches directionnelles (Haut/Bas/Gauche/Droite), ce qui sélectionne automatiquement l'option. On sort du groupe avec Tab.

3. Code source

HTML

La structure sémantique parfaite pour un groupe de contrôles.

<fieldset>
  <legend>Choisissez vos options :</legend>
  <div class="choice-group">
    <label>
      <input type="checkbox" name="options" value="1">
      Option 1
    </label>
    <label>
      <input type="checkbox" name="options" value="2" checked>
      Option 2
    </label>
  </div>
</fieldset>

CSS

Il utilise la propriété appearance: none pour effacer le style du navigateur, et recrée une case à cocher personnalisée grâce aux pseudo-éléments ::before (pour dessiner une encoche purement en CSS, sans charger de SVG externe !).

Pour créer l'encoche (« ✓ » de validation) dans la case à cocher, la méthode traditionnelle est de charger un SVG ou une image de fond. Ici, j'ai utilisé une astuce extrêmement performante : le clip-path.

On crée un carré avec la couleur du fond (var(--bg-color)), et on « découpe » ce carré en forme d'encoche grâce au clip-path.

Avantage Écologique : Zéro requête réseau, zéro base64 encombrant dans le CSS.

.choice-group {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.choice-group label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  cursor: pointer;
  font-weight: 700;
}

/* Boutons radio personnalisés et accessibles */
.choice-group input[type="radio"] {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  border: 2px solid var(--border-color);
  border-radius: 50%;
  background-color: transparent;
  margin: 0;
  cursor: pointer;
  display: grid;
  place-content: center;
}

.choice-group input[type="radio"]::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  transform: scale(0);
  transition: 120ms transform ease-in-out;
  background-color: var(--text-color);
}

.choice-group input[type="radio"]:checked::before {
  transform: scale(1);
}

/* Boutons checkbox personnalisés et accessibles */
input[type="checkbox"] {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  border: 2px solid var(--border-color);
  border-radius: 10%;
  background-color: transparent;
  margin: 0;
  cursor: pointer;
  display: grid;
  place-content: center;
}

input[type="checkbox"]::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 10%;
  transform: scale(0);
  transition: 120ms transform ease-in-out;
  background-color: var(--text-color);

  /* L'encoche en pur CSS (Éco-conception : 0 octet réseau) */
  box-shadow: inset 1em 1em var(--bg-color);
  transform-origin: bottom left;
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
}

input[type="checkbox"]:checked::before {
  transform: scale(1);
}

input[type="checkbox"]:checked {
  background-color: var(--text-color);
}

input[type="checkbox"]:checked::before {
  transform: scale(1);
}