De quoi parle-t-on ?
Dans ce tuto, je vous propose de combiner certaines fonctionnalités trop souvent sous cotées du HTML / CSS pour créer des placeholders sur-mesure qui donneront à vos formulaires cette saveur si particulière !
Squelette
Pour ce faire, merci de vous munir d’un formulaire vierge, d’y incorporer des champs d’identifiant et de mot de passe avec leurs labels associés, ainsi qu’un petit bouton de soumission des familles. Voilà, les ingrédients sont réunis dans notre fichier html pour mener notre expérience à bien !
En l’état le rendu sent un peu la tristesse, alors permettons-nous de l’égayer un peu avec ce fichier de mise en forme formulaire.css avant d’aller plus loin :
Nous voilà donc avec la base de travail suivante :
C’est très light, oui, mais nous n’aurons pas besoin de plus que ça pour jouer aux apprentis sorciers.
Il est maintenant temps d’animer les champs en transformant les labels en placeholder et vice versa.
Placeholder et focus de champ
Pour commencer, complétons notre CSS en positionnant les labels en relatif, puis en les descendant de 30px.
Rappel : un élément avec la propriété CSS position à static (valeur par défaut) ne peut pas être repositionné dans le flux normal. Dans notre cas, nous avons besoin de positionner les labels sur leurs inputs respectifs afin de les transformer en placeholder, d’où le positionnement en relatif et l’écart de la borne haute des labels de 30px.
Ensuite, le but sera de faire en sorte que lors du clic sur un input de saisie, le placeholder vienne se placer 30px plus haut lors d’une transition. Et là, des petites modifications s’imposent:
- Pour que le placeholder transite vers le haut de l’input, il faut qu’un événement survienne. Cet événement est le focus de l’input par le pointer. Sauf que pour appliquer un style sur un élément “à cause” d’un autre élément, il faut que cet autre élément, déclencheur de l’événement, apparaisse avant (dans le HTML). Dans notre cas, puisque nous voulons que le focus sur l’input ait un impact sur la position du label, il faudrait que l’input soit placé avant le label (dans le HTML) pour que le style de ce dernier puisse évoluer.
- Mais ce n’est pas tout, en intervertissant le label et l’input, l’ordre d’empilement des éléments HTML a été modifié et le label empêche le curseur de focus l’input.
Donc si nous reprenons, pour chaque champ input, nous devons mettre le label à la place de l’input et inversement, sinon l’événement de clic n’aura pas d’impact sur le label :
Et n’oublions pas de modifier le CSS du label en remplaçant ‘top:30px’ par ‘bottom:30px’ :
Après ça, il faudra être capable de focus les inputs de saisie malgré les labels qui se trouvent juste devant. Et il existe plusieurs solutions dont une qui utilise le z-index. Il suffira alors de mettre le z-index des inputs supérieur à celui des labels en mettant un background transparent…
Ça fonctionne, mais le problème c’est qu’en touchant au z-index, nous modifions l’affichage naturel d’un élément avec une certaine valeur de profondeur. Et prendre le risque de faire ça, c’est prendre le risque de le refaire plus tard avec un autre élément pour lequel on devra mettre une valeur différente et ainsi de suite, jusqu’à avoir des z-index de partout. Dans le cadre d’un formulaire, vous me direz qu’il n’y a pas de mal, mais si on peut s’en passer au profit d’une solution plus propre, pourquoi pas.
Et justement, HTML nous propose une solution toute simple qui fait très bien le café : L’attribut for de la balise label :
Il permet de lier un label à un champ de type input de tel sorte que lorsqu’une action de clic (ou de touché, pour les smartphones) est réalisée sur le label, cette action est reflétée sur l’input. Et c’est exactement ce que l’on veut : au clic sur le placeholder, le champ input est focus !
Occupons nous à présent de la transition en l’ajoutant à notre formulaire.css :
A ce stade, au clic sur les champs identifiant et mot de passe, le placeholder vient bien se positionner au-dessus. C’est super, ça à l’air de fonctionner ! A un détail près :
Le curseur reste en forme de flèche. Pas super pour indiquer qu’on est susceptible de valoriser un input.
No problemo, on corrige tout ça de suite avec l’attribut CSS “pointer-events” qui indiquera si oui ou non l’élément pointé par le curseur est une cible. En ce qui nous concerne, en indiquant que notre label n’est pas une cible, avec un pointer-events valué à “none”, la prochaine cible sera l’élément juste derrière. En l’occurrence, l’input.
Note : Il est aussi possible de modifier la propriété “cursor” lors d’un hover sur le label pour quelques lignes de plus.
Le formulaire devrait maintenant ressembler à quelque chose comme ceci :
Dans notre élan on tente d’écrire un identifiant random, ou bien on pianote un mot de passe en suivant l’ordre des touches sur le clavier, mais quoi qu’il en soit, on arrive à la même conclusion : le placeholder retombe sur le champ au dé-focus !
Ah mais attendez, pour que le placeholder vienne se positionner en haut à gauche de l’input, il a fallu que ce dernier passe par un état particulier, le focus. Mais nous, à présent, nous avons besoin qu’en enlevant le focus, le placeholder reste où il est si un texte est renseigné. Bon, il n’y a pas trente-six solutions, il va falloir leur trouver un état à nos bons vieux inputs, et c’est ce que l’on va voir tout de suite.
Gestion d’erreurs de surface
HTML permet de gérer une partie des erreurs grâce à certains attributs. Prenons par exemple l’attribut “type” de la balise input. Si nous mettons type=”email” au lieu de type=”text” et que nous cliquons sur le bouton d’envoi du formulaire après avoir renseigné l’input d’une suite de caractères ne formant pas un email, comme “toto007”, une bulle apparaît indiquant que l’email n’est pas valide !
De même, si l’on décide que l’email doit être obligatoire, il existe un attribut : “required”. Et à ce moment-là, si le champ est vide lors de la soumission du formulaire, une bulle surgit en disant qu’il faut renseigner le champ en question.
Ces comportements sont bien utiles puisqu’ils nous permettent d’avoir des messages par défaut lorsqu’un contrôle de surface retourne un message d’erreur. Et d’ailleurs, si vous voulez en savoir plus sur le fonctionnement, je vous propose d’aller jeter un œil sur ce lien : https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation.
Les états de nos inputs peuvent être qualifiés dans le code CSS via les pseudo-classes :valid et :invalid !
Voilà, donc mettons cette technique à profit pour corriger notre dernier problème de label qui retombe.
Pour faire simple, nous avions besoin d’un comportement particulier afin que le label reste en haut à partir du moment où un texte est dedans. C’est pour cela que nous allons utiliser une des pseudo-classes citées précédemment.
Ce qui va se traduire pour nous par quelque chose comme :
“Il faut que le label reste dans sa position haute lorsqu’une chaîne de caractères valide est présente”.
Qu’est-ce que cela donnerait en HTML ?
Ensuite, notre CSS prendra le relais avec la pseudo-classe “:valid” en ajoutant la ligne de sélecteur suivante à la partie de style qui s’occupe de faire remonter de 60px les labels des inputs lors de leur focus :
On ouvre un œil, puis l’autre… Ouf ! Nous obtenons bien ce que nous voulions!
Comme vous l’avez remarqué, nous sommes assez limités dans notre gestion du comportement du label au dé-focus. Si nous désirons faire en sorte que le label reste aussi en haut lorsque le contenu du champ est invalide, nous nous retrouverons avec un label qui restera en haut quelle que soit la situation, et du coup… et bien il n’y a plus aucun intérêt.
Le but ici est surtout de vous montrer l’utilisation que l’on peut faire de ces pseudo-classes. Nous aurions pu aussi les utiliser pour encadrer en rouge les inputs invalides et en vert les inputs valides.
Bon, vous allez me dire qu’on se prend pas mal la tête alors que HTML5 propose l’attribut “placeholder”. Oui mais :
- Il existe des problèmes de compatibilité avec les versions de certains navigateurs (IE9 et en dessous, ou Opera 10.1 par exemple)
- Nous on veut un placeholder qui se transforme en label en transitant vers le haut 🙂
Maintenant, grâce à nos inputs customisés, notre formulaire n’a plus à rougir de ses placeholders. C’est gagné !
Et pour conclure
Nous y voilà, un petit formulaire de connexion qui en apparence ne paye pas de mine, mais qui recèle une bonne dose de CSS pour presque deux fois moins de HTML.
En résumé, ce tuto nous a fait utiliser :
- Le mécanisme d’étiquetage de la balise label sur un contrôle (input) en utilisant l’attribut for, suivi de l’identifiant du contrôle.
- La pseudo-class :valid (ou :invalid), pour simuler la présence d’un élément valide dans le champ et ainsi garder le label surélevé au dé-focus. Bien entendu dans notre cas son utilisation est limitée puisque le seul attribut de validation est required.
Il est important aussi de porter l’attention sur l’aspect organisation du code HTML. Comme on a pu le constater, nous avons été obligés d’intervertir les balises label et input pour que l’input puisse avoir un effet sur le label.
Enfin, gardons à l’esprit que plus il y a d’effets de style et d’éléments qui entrent en contact ou qui sont animés, plus les performances chutent ! CSS3 peut être très gourmand en ressources et il n’est pas rare de voir de la latence sur certains appareils (mobiles par exemple).
Alexandre PETIT – Développeur chez Kaibee