Chapitre 11 : Gestion des états de formulaire avec :checked et :disabled
Contrôle visuel des inputs via les pseudo-classes d'état de formulaire
Dans le développement d'interfaces modernes, le formulaire n'est pas un élément statique. C'est un dialogue entre l'utilisateur et l'application. Pour que ce dialogue soit fluide, l'utilisateur doit savoir instantanément si une option est sélectionnée, si un champ est bloqué ou si une action est impossible.
En CSS, nous gérons cela grâce aux pseudo-classes d'état. Contrairement aux classes classiques que l'on ajoute via JavaScript, les pseudo-classes sont déclenchées nativement par le navigateur en fonction de l'état interne de l'élément HTML.
La pseudo-classe :checked
1. Quoi
La pseudo-classe :checked est un sélecteur qui cible tout élément de formulaire qui est actuellement sélectionné ou coché. Elle s'applique principalement aux éléments suivants :
<input type="checkbox">(cases à cocher)<input type="radio">(boutons radio)<option>(dans une liste déroulante<select>, bien que moins couramment stylisée ainsi)
C'est un état binaire : soit l'élément est coché, soit il ne l'est pas.
2. Pourquoi
L'utilité de :checked dépasse le simple fait de changer la couleur d'une case. En milieu professionnel, on l'utilise pour :
- Améliorer l'accessibilité : Donner un feedback visuel fort pour les utilisateurs malvoyants.
- Créer des composants personnalisés : Les cases à cocher natives sont très difficiles à styliser. On utilise souvent
:checkedcombiné avec le sélecteur adjacent (+) ou général (~) pour styliser un élément décoratif (comme un<span>ou un<div>) à la place de l'input natif. - Logique d'interface sans JS : Créer des menus accordéons ou des onglets simples en utilisant la technique du "Checkbox Hack".
3. Comment
A. Syntaxe de base
Voici comment changer la couleur de bordure d'un input quand il est coché :
input[type="checkbox"]:checked {
outline: 2px solid blue;
background-color: lightblue;
}
B. Cas concret : Case à cocher personnalisée
Comme on ne peut pas modifier l'apparence interne d'une checkbox nativement de manière cohérente sur tous les navigateurs, la méthode standard consiste à masquer l'input et à styliser un label associé.
<div class="custom-checkbox">
<input type="checkbox" id="terms" class="hidden-checkbox" />
<label for="terms" class="checkbox-label">
<span class="checkmark"></span>
J'accepte les conditions générales
</label>
</div>
/* On masque l'input natif mais on le garde accessible pour le clavier */
.hidden-checkbox {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
/* Le style de base de notre fausse case */
.checkmark {
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid #ccc;
border-radius: 4px;
vertical-align: middle;
margin-right: 10px;
transition: all 0.2s ease;
}
/*
C'est ici que la magie opère :
"Quand l'input est :checked, cible le .checkmark qui se trouve
dans le label qui suit immédiatement"
*/
.hidden-checkbox:checked + .checkbox-label .checkmark {
background-color: #007bff;
border-color: #007bff;
}
/* Ajout d'un indicateur visuel (le check) via un pseudo-élément */
.hidden-checkbox:checked + .checkbox-label .checkmark::after {
content: '✓';
color: white;
display: block;
text-align: center;
font-size: 14px;
line-height: 20px;
}
C. Limitations
- Sélecteurs descendants :
:checkedne peut pas cibler un élément parent. Vous ne pouvez pas dire "si l'input est coché, change la couleur du fond de ladivparente" (bien que le nouveau sélecteur:has()commence à rendre cela possible dans les navigateurs modernes). - Accessibilité : Si vous masquez l'input natif, assurez-vous que le focus reste visible (via
:focus-visible) pour les utilisateurs naviguant au clavier.
4. Zone de Danger
❌ Erreur commune : Essayer de styliser l'input natif avec background-color et s'étonner que cela ne fonctionne pas sur Safari ou Chrome.
✅ Bonne pratique : Masquer l'input natif et utiliser :checked + label pour créer un design totalement contrôlé et cohérent.
Flux de gestion des états de formulaire
La pseudo-classe :disabled
1. Quoi
La pseudo-classe :disabled cible tout élément de formulaire qui possède l'attribut HTML disabled. Elle s'applique à presque tous les éléments de saisie :
<input>(text, email, password, checkbox, radio, etc.)<button><select><textarea>
Un élément désactivé ne peut pas recevoir le focus, ne peut pas être modifié par l'utilisateur et n'est pas envoyé lors de la soumission du formulaire.
2. Pourquoi
L'aspect visuel d'un champ désactivé est crucial pour l'expérience utilisateur (UX) :
- Prévention d'erreurs : Indiquer clairement qu'une action est impossible tant qu'une condition n'est pas remplie (ex: le bouton "Envoyer" est désactivé tant que l'email n'est pas valide).
- Hiérarchie d'information : Montrer des données en lecture seule qui ne doivent pas être modifiées.
- Guidage : Forcer l'utilisateur à suivre un ordre précis de remplissage.
3. Comment
A. Syntaxe de base
input:disabled {
background-color: #f5f5f5;
color: #999;
cursor: not-allowed; /* Change le curseur en signe "interdit" */
}
B. Cas concret : Bouton de validation conditionnel
Imaginons un bouton qui doit être visuellement "éteint" tant que l'utilisateur n'a pas coché la case "CGU".
<form>
<div class="field">
<input type="checkbox" id="agree" />
<label for="agree">J'accepte les conditions</label>
</div>
<button type="submit" id="submit-btn" disabled>
Créer mon compte
</button>
</form>
#submit-btn {
padding: 10px 20px;
background-color: #28a745;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: opacity 0.3s ease;
}
/* Style spécifique quand le bouton est désactivé */
#submit-btn:disabled {
background-color: #cccccc;
color: #666666;
cursor: not-allowed;
opacity: 0.7;
/* On retire les effets de survol pour éviter la confusion */
pointer-events: none;
}
C. Limitations
- Spécificité :
:disableda une priorité forte, mais peut être écrasé par des sélecteurs d'ID ou des styles inline. - Interaction : Un élément
:disabledne déclenche aucun événement JavaScript (click,mouseover, etc.). Si vous avez besoin de déclencher un message d'erreur au clic sur un champ "bloqué", vous ne devez pas utiliserdisabledmais plutôt un attribut personnalisé ou une classe, tout en gérant l'accessibilité.
4. Zone de Danger
❌ Erreur commune : Utiliser uniquement une couleur grise pour indiquer qu'un champ est désactivé sans ajouter l'attribut HTML disabled. L'utilisateur pourra toujours cliquer dedans, créant une frustration immense.
✅ Bonne pratique : Toujours coupler le style :disabled avec l'attribut HTML disabled pour garantir que le comportement technique correspond au signal visuel.
Questions clés
Q1 : Quelle est la différence fondamentale entre :checked et :disabled ?
Découvrir la réponse
:checked est un état de sélection (est-ce que l'option est choisie ?), tandis que :disabled est un état de disponibilité (est-ce que l'élément est utilisable ?).
Q2 : Pourquoi utiliser :checked + label plutôt que de styliser directement l'input ?
Découvrir la réponse
Parce que les navigateurs limitent drastiquement la personnalisation visuelle des inputs de type checkbox et radio. En ciblant le label (ou un élément enfant du label), on peut créer n'importe quel design tout en conservant la fonctionnalité native.
Q3 : Est-ce que :disabled fonctionne sur un élément <div> ?
Découvrir la réponse
Non. La pseudo-classe :disabled ne fonctionne que sur les éléments de formulaire interactifs. Pour un div, il faudra utiliser une classe CSS (ex: .is-disabled) et gérer l'interactivité via JavaScript ou pointer-events: none.
Q4 : Comment s'assurer qu'un champ désactivé reste accessible ?
Découvrir la réponse
Bien que :disabled retire le champ de la tabulation clavier, il est important que le contraste de couleur reste suffisant pour que l'utilisateur puisse au moins lire l'information contenue dans le champ.
Mise en pratique
Exercice 1 : Reproduction guidée
Objectif : Créer un champ de saisie texte qui change de couleur de fond lorsqu'il est désactivé.
- Créez un
<input type="text">avec une valeur par défaut. - Ajoutez l'attribut
disabledà cet input. - En CSS, utilisez la pseudo-classe
:disabledpour mettre le fond en gris clair (#eee) et le texte en gris foncé (#777).
Découvrir la solution commentée
<input type="text" value="Ce champ est bloqué" disabled />
/* CSS */
input:disabled {
background-color: #eee; /* Fond gris pour signifier l'inactivité */
color: #777; /* Texte atténué */
border: 1px solid #ccc;
padding: 8px;
}
Exercice 2 : Adaptation
Objectif : Créer un groupe de boutons radio personnalisés.
- Créez trois boutons radio pour choisir une taille (S, M, L).
- Masquez les inputs radio natifs.
- Stylisez des labels pour qu'ils ressemblent à des boutons.
- Utilisez
:checkedpour que le bouton sélectionné change de couleur de fond (ex: bleu) et de couleur de texte (blanc).
Découvrir la solution commentée
<div class="size-picker">
<input type="radio" name="size" id="s" value="s" checked />
<label for="s">S</label>
<input type="radio" name="size" id="m" value="m" />
<label for="m">M</label>
<input type="radio" name="size" id="l" value="l" />
<label for="l">L</label>
</div>
/* Masquage des radios natifs */
.size-picker input[type="radio"] {
display: none;
}
/* Style des labels comme des boutons */
.size-picker label {
display: inline-block;
padding: 10px 20px;
border: 2px solid #007bff;
color: #007bff;
cursor: pointer;
border-radius: 5px;
margin-right: 5px;
transition: all 0.2s;
}
/* État sélectionné : on cible le label qui suit l'input coché */
.size-picker input[type="radio"]:checked + label {
background-color: #007bff;
color: white;
}
Exercice 3 : Conception
Objectif : Créer un "Interrupteur" (Toggle Switch) moderne.
Le HTML de départ est fourni, concentrez-vous uniquement sur le CSS.
<div class="switch-container">
<input type="checkbox" id="wifi" class="toggle-input" />
<label for="wifi" class="toggle-label"></label>
<span>Wi-Fi</span>
</div>
Étapes de base :
- Masquez l'input natif (il reste fonctionnel, seul le label sera visible).
- Stylisez
.toggle-labelpour qu'il ressemble à une pilule (border-radiusélevé, dimensions fixes). - Utilisez
:checked + .toggle-labelpour passer le fond de gris à vert quand la case est cochée. - Ajoutez une
transitionsur la couleur de fond.
Bonus (optionnel — fait appel aux pseudo-éléments) :
- Ajoutez un cercle blanc qui se déplace de gauche à droite lors du clic. Pour cela, créez ce cercle via
.toggle-label::after(pseudo-élément CSS) et déplacez-le avectransform: translateX(...)sur l'état:checked. - Ajoutez un second switch avec l'attribut
disabledet stylisez son état grisé via:disabled + .toggle-label.
Découvrir la solution commentée
<div class="switch-container">
<input type="checkbox" id="wifi" class="toggle-input" />
<label for="wifi" class="toggle-label"></label>
</div>
<div class="switch-container">
<input type="checkbox" id="wifi-off" class="toggle-input" disabled />
<label for="wifi-off" class="toggle-label"></label>
<span>(Désactivé)</span>
</div>
.switch-container {
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
/* Masquage de l'input */
.toggle-input {
display: none;
}
/* Le corps du switch */
.toggle-label {
width: 50px;
height: 26px;
background-color: #ccc;
border-radius: 13px;
position: relative;
cursor: pointer;
transition: background-color 0.3s;
}
/* Le cercle blanc */
.toggle-label::after {
content: '';
position: absolute;
width: 22px;
height: 22px;
background-color: white;
border-radius: 50%;
top: 2px;
left: 2px;
transition: transform 0.3s;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
/* État Coché : Fond vert et déplacement du cercle */
.toggle-input:checked + .toggle-label {
background-color: #4cd964;
}
.toggle-input:checked + .toggle-label::after {
transform: translateX(24px);
}
/* État Désactivé : On cible le label quand l'input est :disabled */
.toggle-input:disabled + .toggle-label {
background-color: #e0e0e0;
cursor: not-allowed;
opacity: 0.6;
}
/* Empêcher le mouvement si désactivé (même si l'input est coché) */
.toggle-input:disabled + .toggle-label::after {
background-color: #f0f0f0;
}