Validation de formulaire en CSS

Valider un formulaire en CSS

J’aime me mettre dans l’esprit « pourquoi le faire en JS quand CSS peut le faire ? ». Une fois bien maîtrisé, le CSS peut se révéler très puissant et permet de créer (par exemple) des jeux très simples, ou ce genre de projets. Je vous invite d’ailleurs à suivre la page Facebook de Steloria ou son Twitter, nous publions tous les mercredis des projets Codepen (essentiellement en CSS).

Je vous propose donc aujourd’hui de voir une façon assez simple de vérifier la validité (ou non) d’un formulaire uniquement en utilisant du HTML/CSS. L’idée étant de ne pas pouvoir valider le formulaire tant que tous les champs ne sont pas remplis, que le mail n’est pas valide et que le mot de passe est trop court. Voilà un aperçu du résultat:

See the Pen Pure CSS form validation by Fehrenbach Baptiste (@medrupaloscil) on CodePen.0

Le HTML

Nous allons donc commencer par notre HTML, qui est on ne peut plus basique:

<form method="POST">
	<input type="text" name="name" placeholder="Full Name">
	<input type="email" name="email" placeholder="Email">
	<input type="password" name="password" placeholder="Password">
	<p>The password must be > 4 char</p>
	<input type="submit" value="Register" disabled>
	<input type="submit" value="Register">
</form>

Nous allons ici utiliser trois input différents pour récupérer le nom, l’email et le mot de passe de l’utilisateur. Nous allons également ajouter une petite précision sur la longueur du mot de passe (qui ne s’affichera que quand l’utilisateur remplira ce dernier).

Notez cependant l’utilisation de deux input de type submit. Il existe plusieurs méthodes pour empêcher un utilisateur d’interagir avec un élément. Cependant les méthodes utilisant uniquement du CSS ne permettent pas (à ma connaissance du moins) de bloquer totalement l’interaction. Vous pouvez par exemple mettre un « pointer-events: none; » qui empêche tout clic (sur Desktop comme sur mobile) mais vous n’empêcherez pas sa sélection avec un tab. L’idée est donc d’avoir un input disabled (qui lui ne peut pas être sélectionné) et un autre caché.

Ajouter des restrictions

Nous allons maintenant rajouter certaines restrictions sur les champs. Pour commencer nous allons mettre tous les champs en required. Pour le nom d’utilisateur nous n’allons pas avoir besoin de restrictions supplémentaires. Pour le password nous allons utiliser l’attribut « minlength » pour forcer l’utilisateur à entrer un mot de passe d’au moins 4 caractères.

Pour l’email c’est une autre paire de manches. HTML comprend plus où moins ce qu’un mail est, mais il considère comme valide « t@t ». Or, nous voulons que l’utilisateur rentre un email du type « aaa@bbb.cc ». Pour cela, HTML dispose d’un attribut très pratique: pattern. Le pattern prend en valeur une regexp et vérifie automatiquement sa validité (et est plutôt bien accepté par les navigateurs). À partir de là soit vous êtes fou et vous pouvez écrire la regexp tout seul, soit vous pouvez la récupérer sur StackOverflow comme tout le monde. Nous obtenons donc le HTML suivant:

<form method="POST">
	<input type="text" name="name" placeholder="Full Name" required>
	<input type="email" name="email" placeholder="Email" required pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$">
	<input type="password" name="password" placeholder="Password" required minlength="4">
	<p>The password must be > 4 char</p>
	<input type="submit" value="Register" disabled>
	<input type="submit" value="Register">
</form>

Mettons le tout en forme

Nous allons donc pouvoir commencer à styliser notre formulaire. Pour commencer, je prépare toujours mon body de la même façon pour centrer le projet:

body {
	display: flex;
	justify-content: center;
	align-items: center;
	height: 100vh;
	font-family: sans-serif;
}

Nous allons ensuite mettre en forme le formulaire. Pour ça je suis resté sur quelque chose de sobre:

form {
	width: 300px;
	padding: 40px;
	box-sizing: border-box;
	border-radius: 3px;
	box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.3);
}
input {
	display: block;
	width: 100%;
	margin-bottom: 15px;
	padding: 10px;
	box-sizing: border-box;
	font-size: 15px;
	border: 1px solid #bbb;
	border-radius: 3px;
}

Afficher des instructions

Nous allons maintenant passer au style de notre paragraphe. Par défaut nous voulons qu’il soit caché (et pas trop visible non plus). J’ai également utilisé un translate qui n’a d’autre utilité que de m’éviter d’avoir à gérer les marges de mes inputs. Vous pouvez gérer son affichage de la manière qu’il vous plait:

p {
	display: none;
	font-size: 12px;
	margin: 0;
	transform: translateY(-10px);
	color: #666;
}

Maintenant pour afficher le paragraphe uniquement, nous allons passer par le sélecteur « + » dont je vous avais parlé dans l’article sur le chronomètre. Pour faire court, il permet de sélectionner un élément du même parent situé directement après ce qu’on met à sa gauche:

input:focus + p {
	display: block;
}

Ici, nous voulons donc mettre en block tous les <p> situés directement après un input qui est focus par l’utilisateur. Sans avoir à ajouter de CSS, vous pouvez donc ajouter d’autres instructions sous les autres inputs. Ils réagiront tous de la même façons.

Et la touche finale

Nous allons donc pouvoir passer aux inputs. Je leur donne par défaut le même style et je les cache. Puis j’affiche l’input disabled et je lui donne un style un peu plus « disabled »:

input[type="submit"] {
	border: none;
	background-color: #8BC34A;
	color: #fff;
	display: none;
}
input[type="submit"]:disabled {
	background-color: #F44336;
	display: block;
	opacity: 0.9;
}

Et c’est là que la magie opère ! Dans l’article sur le chronomètre je vous avais également parlé du « ~ » qui agit comme le « + » mais sur tous les éléments suivants. Nous allons donc vérifier que nos trois inputs sont valides, et s’il le sont inverser l’affichage des deux submits. Et comme le CSS considère comme valide ce que le HTML considère comme valide, il prendra en compte le minlength et le pattern:

input:valid ~ input:valid ~ input:valid ~ input[type="submit"]:disabled {
	display: none;
}
input:valid ~ input:valid ~ input:valid ~ input[type="submit"]:not(:disabled) {
	display: block;
	cursor: pointer;
}

Ici nous demandons donc à cibler un submit situé après un input valide, lui-même situé après un input valide, lui même situé après un input valide. Ce code ne s’exécutera donc que quand les trois inputs seront remplis.

Limites de cette méthode

Si on oublie les soucis de compatibilité (cette méthode est compatible avec quasiment tous les navigateurs récents), le soucis majeur de cette méthode est son manque de flexibilité au niveau de la structure du formulaire. En effet, si vous enfermez un de vos inputs dans un conteneur (par exemple pour les mettre côte-à-côte, ou pour styliser le label avec) vous ne pourrez plus vérifier sa validité. Pour des petits formulaires simple elle conviendra donc parfaitement, mais si vous avez besoin de quelque chose de plus gros elle deviendra un obstacle plus qu’autre chose.

Laisser un commentaire