Cours CSS / états des formulaires : focus, validation, disabled et readonly
Le CSS peut styliser le focus, la validité et les contrôles de formulaire désactivés ou en lecture seule, mais le HTML définit leurs étiquettes, contraintes et comportement d'envoi. :invalid peut correspondre avant l'interaction, tandis que :user-invalid aide à retarder le style des erreurs jusqu'à ce que le navigateur le juge approprié.
Associez étiquettes et instructions aux contrôles
Associez l’attribut for de label à l’id du champ correspondant. Le libellé reste ainsi lié au contrôle. Le texte placeholder disparaît pendant la saisie et ne remplace ni ce libellé ni une consigne importante. Gardez les explications complémentaires visibles et référencez leur identifiant avec aria-describedby.
<label for="email">Email address (required)</label>
<input id="email" name="email" type="email" required
placeholder="name@example.com" aria-describedby="email-help">
<p id="email-help">Enter name@example.com in the same format.</p>
Cet extrait reprend le champ email de l’exemple complet. id identifie un élément dans le document ; name définit sa clé dans les données soumises. Un champ dépourvu de name n’est généralement pas inclus dans ces données, même si la saisie reste possible. Pour associer les libellés et les explications, consultez le guide W3C des libellés de formulaire et le guide W3C des consignes de saisie.
Dimensionner les contrôles pour les petits écrans et le texte agrandi
Si vous vous fiez uniquement à la largeur inhérente de la fenêtre de saisie, elle peut dépasser un écran étroit lorsque la taille de la police est augmentée. Définissez la largeur maximale du formulaire et utilisez width: 100% et box-sizing: border-box ensemble dans la fenêtre de saisie. Cela garantira que la bordure et le remplissage sont également inclus dans la largeur spécifiée.
*, *::before, *::after { box-sizing: border-box; }
form { max-width: 28rem; }
input { width: 100%; min-width: 0; padding: .65rem; font: inherit; }
Cette règle est incluse dans la section de style de l'exemple entier. font: inherit permet à la fenêtre de saisie et aux boutons de suivre la police, la taille et la hauteur de ligne du texte, et min-width: 0 lève une contrainte de taille minimale qui pourrait empêcher le rétrécissement même lors de l'insertion de la fenêtre de saisie dans un Flexbox/Grid. Une hauteur fixe n'est pas utilisée afin que les éléments en dessous se déplacent naturellement vers le bas même lorsque la description est augmentée ou que les lettres sont agrandies.
Séparer l'état de focus et les erreurs de validation
:focus correspond à l'élément qui a actuellement le focus, et :focus-visible correspond si le navigateur détermine qu'il doit afficher le focus. Il est principalement affiché lors de la navigation au clavier, mais il peut également être affiché en cliquant avec la souris dans la fenêtre de saisie de texte, donc il ne faut pas le comprendre comme « s'applique uniquement au clavier ». la documentation MDN sur :focus-visible . Pour appliquer l'indication de focus de manière cohérente aux liens également, comparez CSS États des liens et focus clavier visible.
Le focus indique l'élément que vous manipulez actuellement, et les erreurs indiquent les éléments qui n'ont pas satisfait les conditions d'entrée. Comme les deux états peuvent être présents en même temps, l'exemple entier montre le focus avec un contour bleu et l'erreur avec une bordure rouge foncé et une déclaration d'erreur. Laissez un peu de place autour du contour pour éviter de le tronquer, et évitez de supprimer le contour sans fournir un autre indicateur de focus.
:invalid correspond si la valeur actuelle est invalide, donc un champ obligatoire vide est également pris en compte dès le début. :user-invalid correspond lorsque le navigateur affichera une condition d'erreur après une interaction de l'utilisateur. Le moment où vous affichez quelque chose, par exemple quand vous avez fini de taper ou lorsque vous tentez de soumettre, peut dépendre du comportement de votre navigateur. Le laboratoire vérifie les erreurs en appuyant sur le bouton Soumettre. Consultez la documentation MDN sur :user-invalid .
Si vous devez prendre en compte des cibles de support plus anciennes, vous devez vérifier si le sélecteur est pris en charge et concevoir un flux de vérification séparé. Même si la décoration d'erreur n'apparaît pas parce que le sélecteur n'est pas pris en charge, cela ne signifie pas que les vérifications de required et de formatage en HTML disparaissent. Choisissez une couleur de focus suffisamment distincte du fond réel, et vérifiez également les conditions d'application du Guide de Contraste Non-Textuel W3C.
Comparer required, valid, disabled et readonly
| situation | signification | Focus et soumission générale |
|---|---|---|
required |
L'utilisateur doit saisir une valeur | Peut recevoir le focus si l'élément est actif ; les valeurs vides sont soumises à validation lors de la soumission |
:valid·:invalid |
Si les conditions de validation HTML sont respectées | Les résultats de vérification sont déterminés indépendamment de la forme de la bordure |
disabled |
Actuellement indisponible | Généralement exclu de la navigation par onglet et des soumissions |
readonly |
Impossible de modifier les valeurs telles que la saisie de texte prise en charge | Peut recevoir le focus et sélectionnable ; si l’attribut name existe, l'inclure dans la soumission |
readonly est pris en charge par certains contrôles de type texte et n'est pas une méthode générale pour rendre un élément select en lecture seule. Les contrôles en lecture seule pris en charge sont exclus de la validation des contraintes, tandis que les contrôles nommés peuvent toujours envoyer des données de formulaire soumises. Il faut distinguer ce comportement de celui des contrôles désactivés. Voir HTML Standard : construction de la liste des entrées, MDN : readonly.
Ce champ email illustre un format tel que name@example.com. Passer sa vérification de validité ne confirme pas que le compte existe ou peut recevoir des courriels. La validation HTML type="email" n’accepte pas tous les formats d’adresses internationalisées ; les parties locales non ASCII ne sont pas présentées ici comme des entrées valides garanties. Pour plus de détails, voir les conditions du champ email dans la norme HTML.
Exécutez l'exemple et inspectez les champs soumis
Enregistrez le code suivant sous form-states.html en UTF-8 et ouvrez-le dans votre navigateur. Le HTML et le CSS déterminent l'état du formulaire. Le court morceau de JavaScript à la fin est un code auxiliaire pour intercepter les soumissions valides et afficher une liste de données à l'écran, sans les envoyer au serveur ni effectuer de vérifications supplémentaires des entrées. Si JavaScript est désactivé, la fonction d'affichage des résultats ne fonctionnera pas.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Comparing form states and submitted fields</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; padding: 1rem; color: #183044; font-family: sans-serif; line-height: 1.6; }
main { max-width: 46rem; margin-inline: auto; }
h1 { font-size: 1.5rem; } h2 { font-size: 1.2rem; }
button, input { font: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 3px solid #164f73; outline-offset: 3px; }
form { max-width: 28rem; }
.field { margin-block: 1.25rem; }
label { display: block; margin-bottom: .35rem; font-weight: 700; }
input { display: block; width: 100%; min-width: 0; padding: .65rem;
border: 2px solid #6d7e8b; border-radius: .3rem; background: white; color: #183044; }
input:required { border-inline-start-width: 4px; }
input:user-invalid { border-color: #9d2632; }
.help, .error { margin-block: .4rem 0; }
.error { display: none; color: #9d2632; }
input:user-invalid + .error { display: block; }
input[readonly] { background: #eef6fa; }
input:disabled { background: #eceff2; color: #465766; cursor: not-allowed; }
button { padding: .65rem 1rem; border: 1px solid #164f73; border-radius: .3rem;
background: #166b92; color: white; }
output { display: block; margin-block: 1rem; white-space: pre-wrap; overflow-wrap: anywhere; }
</style>
</head>
<body>
<main>
<h1>Check input states and submitted data</h1>
<form id="demo-form">
<div class="field">
<label for="email">Email address (required)</label>
<input id="email" name="email" type="email" autocomplete="email" required
placeholder="name@example.com" aria-describedby="email-help email-error">
<p id="email-error" class="error">Enter an email address in a format such as name@example.com; do not leave the field empty.</p>
<p id="email-help" class="help">This sample input checks the address format. It does not check whether the example address receives mail.</p>
</div>
<div class="field">
<label for="plan">Plan (read-only)</label>
<input id="plan" name="plan" type="text" value="Basic" readonly>
</div>
<div class="field">
<label for="coupon">Coupon (currently disabled)</label>
<input id="coupon" name="coupon" type="text" value="WELCOME" disabled>
</div>
<button type="submit">Check submitted fields</button>
</form>
<output id="result" for="email plan coupon" aria-live="polite"></output>
<script>
const form = document.getElementById("demo-form");
form.addEventListener("submit", (event) => {
event.preventDefault();
const entries = Array.from(new FormData(form).entries());
document.getElementById("result").textContent = JSON.stringify(entries, null, 2);
});
</script>
</main>
</body>
</html>
- Laissez le champ email vide et cliquez sur « Check submitted fields ». Vérifiez votre navigateur pour les instructions sur les entrées requises et les messages d'erreur.
- Saisissez
abcdans l'e-mail et soumettez à nouveau. Une nouvelle liste de résultats ne devrait pas s'afficher à cause d'une erreur de format. - Entrez
name@example.comet soumettez. Les résultats contiennent les clés email et plan, mais pas coupon, car ce champ est disabled. - Avec Tab, parcourez le champ email, le champ Plan, puis le bouton de soumission. Les coupons inactifs sont ignorés dans l'ordre normal de tabulation, et les plans en lecture seule peuvent recevoir le focus.
- Supprimez uniquement l’attribut disabled du champ coupon. Vous pouvez alors lui donner le focus et sa valeur est ajoutée à la liste produite lors d’une soumission valide. Rétablissez disabled après la comparaison.
- Supprimez uniquement l'attribut
readonlydu plan et essayez de le modifier. Après la comparaison, rétablissez sa valeur à « Basic » et ajoutez à nouveaureadonly. - Réduisez la largeur de l'écran et ajustez l'agrandissement du navigateur ou les paramètres de taille de police. Vérifiez que la fenêtre de saisie, le contour de focus et les phrases d'erreur ne sont pas coupés ou superposés.
Comprendre les limites du CSS et de la validation du navigateur
Le CSS est responsable de l'affichage de l'état d'un élément. La vérification par le navigateur peut réduire les erreurs de saisie de l'utilisateur, mais elle peut être contournée avec les outils de développement ou des requêtes séparées, donc le service réel doit revérifier les valeurs autorisées, la longueur, les permissions, etc., sur le serveur. Les phrases d'erreur décrivent spécifiquement les éléments problématiques et les solutions, et un flux séparé pour préserver les informations saisies est également conçu lorsqu'une erreur serveur se produit.
Si l’exemple se comporte de manière inattendue, vérifiez les paires for/id, les attributs name et required, le type du champ et ses états disabled ou readonly. Si le focus est invisible, cherchez une règle qui remplace outline. Une erreur visible dès le chargement peut venir de :invalid. Si le message reste masqué après une tentative de soumission, vérifiez la prise en charge de :user-invalid et les combinateurs et pseudo-classes CSS.




