Chapitre 39 : Validation en temps réel avec :valid et :invalid
Concepts clés : Pseudo-classes de validation basées sur les attributs HTML
La validation des formulaires a longtemps été le domaine exclusif du JavaScript. Cependant, avec l'évolution du HTML5 et du CSS3, le navigateur est désormais capable de gérer une grande partie de la logique de validation nativement. Les pseudo-classes :valid et :invalid permettent de transformer l'expérience utilisateur (UX) en fournissant un retour visuel instantané sans écrire une seule ligne de script.
La Validation Native via CSS
1. Quoi
Les pseudo-classes :valid et :invalid sont des sélecteurs CSS qui ciblent les éléments de formulaire (comme <input>, <select>, <textarea>) en fonction de leur état de validité.
L'état de validité est déterminé par le moteur de validation interne du navigateur, qui s'appuie sur les attributs de contrainte HTML5 définis sur l'élément :
required: Le champ ne doit pas être vide.type="email"outype="url": La valeur doit respecter le format standard.pattern="[a-z]+": La valeur doit correspondre à une expression régulière (Regex).min/max: Pour les types numériques ou dates.minlength/maxlength: Pour la longueur du texte.
Lorsqu'un champ respecte toutes ses contraintes, il est considéré comme :valid. S'il en viole au moins une, il devient :invalid.
2. Pourquoi
Dans un projet professionnel, la validation en temps réel est cruciale pour réduire la friction cognitive de l'utilisateur.
Attendre que l'utilisateur clique sur "Envoyer" pour lui afficher une liste d'erreurs en haut de page est une pratique obsolète. En utilisant :valid et :invalid, vous offrez :
- Un feedback immédiat : L'utilisateur sait instantanément s'il a fait une erreur de frappe.
- Une réduction des erreurs de soumission : Le taux de conversion augmente lorsque les erreurs sont corrigées avant l'envoi.
- Une performance accrue : Le style est géré par le moteur de rendu du navigateur, évitant des cycles de re-calcul JavaScript et des manipulations DOM coûteuses.
3. Comment
A. Syntaxe de base
Voici l'implémentation la plus simple pour différencier visuellement un champ correct d'un champ erroné.
/* Champ valide : bordure verte */
input:valid {
border: 2px solid green;
}
/* Champ invalide : bordure rouge */
input:invalid {
border: 2px solid red;
}
B. Cas concret : Formulaire d'inscription robuste
Dans un scénario réel, on ne se contente pas de changer la couleur de la bordure. On utilise souvent des icônes, des messages d'erreur conditionnels et des transitions fluides.
HTML :
<form class="registration-form">
<div class="field-group">
<label for="username">Nom d'utilisateur (3-15 caractères)</label>
<input
type="text"
id="username"
name="username"
required
minlength="3"
maxlength="15"
placeholder="Ex: JeanDupont"
/>
<span class="error-message">Le nom d'utilisateur est requis et doit contenir entre 3 et 15 caractères.</span>
</div>
<div class="field-group">
<label for="email">Email professionnel</label>
<input
type="email"
id="email"
name="email"
required
placeholder="email@entreprise.com"
/>
<span class="error-message">Veuillez saisir une adresse email valide.</span>
</div>
</form>
CSS :
.field-group {
margin-bottom: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
input {
padding: 0.75rem;
border: 2px solid #ccc;
border-radius: 4px;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
/*
On utilise :invalid pour styliser le champ,
mais on masque le message d'erreur par défaut
*/
.error-message {
color: #d32f2f;
font-size: 0.85rem;
display: none;
}
/* Style quand le champ est invalide */
input:invalid {
border-color: #d32f2f;
}
/*
Astuce avancée : Afficher le message d'erreur
uniquement si l'input est invalide
*/
input:invalid + .error-message {
display: block;
}
/* Style quand le champ est valide */
input:valid {
border-color: #388e3c;
background-color: #f1f8e9;
}
C. Limitations et pièges
L'utilisation brute de :invalid présente un défaut majeur d'UX : le champ est marqué comme invalide dès le chargement de la page si l'attribut required est présent. L'utilisateur se retrouve face à un formulaire "tout rouge" avant même d'avoir commencé à taper, ce qui est anxiogène.
Pour pallier cela, on utilise généralement la pseudo-classe :placeholder-shown ou :user-invalid (plus moderne).
:placeholder-shown: Permet de ne pas appliquer le style:invalidtant que l'utilisateur n'a pas commencé à saisir du texte (le placeholder est encore visible).:user-invalid: (Supportée par les navigateurs récents) Ne s'active qu'après que l'utilisateur a quitté le champ (événementblur), évitant ainsi le feedback agressif pendant la frappe.
4. Zone de Danger
❌ Erreur commune : Se fier uniquement au CSS pour la sécurité.
Le CSS et la validation HTML5 sont des outils d'UX (Expérience Utilisateur). Ils ne sont pas des outils de sécurité. Un utilisateur malveillant peut facilement supprimer l'attribut required ou modifier le CSS via l'inspecteur du navigateur.
✅ Bonne pratique : La validation en cascade.
- CSS/HTML5 : Feedback instantané pour l'utilisateur.
- JavaScript : Validation complexe (ex: vérifier si un pseudo est déjà pris en base de données).
- Backend (Node, Python, PHP) : Validation finale et obligatoire avant l'insertion en base de données.
Flux de validation CSS en temps réel
Questions clés
1. Quelle est la différence fondamentale entre :valid et :invalid ?
Découvrir la réponse
:valid cible les éléments dont la valeur actuelle satisfait toutes les contraintes de validation HTML5 (comme required, pattern, type="email"), tandis que :invalid cible ceux qui en violent au moins une.
2. Pourquoi le formulaire apparaît-il en rouge dès l'ouverture si j'utilise :invalid avec required ?
Découvrir la réponse
Parce que le navigateur considère qu'un champ vide avec l'attribut required est, par définition, invalide. Le CSS s'applique donc immédiatement.
3. Comment empêcher l'affichage des erreurs avant que l'utilisateur n'ait interagi avec le champ ?
Découvrir la réponse
On peut combiner :invalid avec :not(:placeholder-shown). Ainsi, le style d'erreur ne s'applique que si le champ est invalide ET que le placeholder a disparu (signifiant que l'utilisateur a saisi quelque chose).
4. Peut-on utiliser des expressions régulières personnalisées avec ces pseudo-classes ?
Découvrir la réponse
Oui, en utilisant l'attribut pattern dans le HTML. Par exemple, pattern="[0-9]{5}" pour un code postal français. Le CSS :valid / :invalid réagira automatiquement à la correspondance de cette Regex.
Mise en pratique
Exercice 1 : Reproduction guidée
Créez un champ de saisie pour un mot de passe qui doit contenir au minimum 8 caractères. Appliquez une bordure bleue quand le champ est vide, rouge quand il est invalide (moins de 8 caractères) et verte quand il est valide.
Une fois l'exercice réalisé, testez le rendu dans le navigateur sans rien taper. La bordure bleue (état "neutre") devrait s'afficher… mais ce n'est pas ce que vous observez. Pourquoi ?
Parce que l'attribut required rend le champ immédiatement invalide dès le chargement de la page (un champ vide + required = :invalid). La règle border-color: red de :invalid écrase donc aussitôt la règle border: 2px solid blue. L'utilisateur ne verra jamais la bordure bleue.
C'est précisément le problème d'UX résolu dans l'Exercice 2 avec :not(:placeholder-shown).
Découvrir la solution commentée
<input type="password" id="pwd" required minlength="8" placeholder="Mot de passe...">
/* CSS */
#pwd {
border: 2px solid blue; /* État neutre/vide */
outline: none;
}
#pwd:invalid {
border-color: red; /* Trop court ou vide */
}
#pwd:valid {
border-color: green; /* 8 caractères ou plus */
}
Exercice 2 : Adaptation
Reprenez l'exercice précédent, mais modifiez le CSS pour que la bordure rouge n'apparaisse que si l'utilisateur a commencé à taper (utilisez :not(:placeholder-shown)).
Découvrir la solution commentée
#pwd {
border: 2px solid blue;
outline: none;
}
/*
On cible l'élément qui est invalide
ET qui n'affiche plus son placeholder
*/
#pwd:invalid:not(:placeholder-shown) {
border-color: red;
}
#pwd:valid {
border-color: green;
}
Exercice 3 : Conception
Créez un formulaire de contact comprenant :
- Un champ "Code Client" qui doit obligatoirement commencer par "CLI-" suivi de 4 chiffres (ex: CLI-1234).
- Un champ "Âge" qui doit être compris entre 18 et 99 ans.
Le formulaire doit afficher un message d'erreur spécifique sous chaque champ uniquement lorsqu'il est invalide et que l'utilisateur a interagi avec.
Propriétés CSS attendues :
| Sélecteur | Propriété | Valeur attendue |
|---|---|---|
.group | display | flex |
.group | flex-direction | column |
.group | margin-bottom | 1rem |
.err | display (état par défaut) | none |
.err | color | red |
.err | font-size | 0.8rem |
input:valid | border | 2px solid green |
input:invalid:not(:placeholder-shown) | border | 2px solid red |
input:invalid:not(:placeholder-shown) + .err | display | block |
Découvrir la solution commentée
<form>
<div class="group">
<label>Code Client :</label>
<input type="text" required pattern="CLI-[0-9]{4}" placeholder="CLI-0000">
<span class="err">Format invalide : CLI- suivi de 4 chiffres.</span>
</div>
<div class="group">
<label>Âge :</label>
<input type="number" required min="18" max="99" placeholder="18-99">
<span class="err">Vous devez avoir entre 18 et 99 ans.</span>
</div>
</form>
.group {
display: flex;
flex-direction: column;
margin-bottom: 1rem;
}
.err {
display: none;
color: red;
font-size: 0.8rem;
}
/*
L'erreur s'affiche seulement si :
1. Le champ est invalide
2. L'utilisateur a commencé la saisie (placeholder disparu)
*/
input:invalid:not(:placeholder-shown) + .err {
display: block;
}
input:valid {
border: 2px solid green;
}
input:invalid:not(:placeholder-shown) {
border: 2px solid red;
}