TL;DR ? Dépôt GitHub, la maquette hébergée sur GitHub et bien évidemment, vous pouvez l'utiliser dans cette page et donc participer au débat.
Ce projet de portage a été rendu public le 13 Novembre 2013, pour la sortie de Dotclear 2.6 et pour l'anniversaire de Kozlika. Annoncé sur le forum à la sortie du billet.
En général, je ne glose pas trop sur les développements que j'utilise pour mon blog. Je me suis rendu compte que par rapport à des confrères, j'étais très timide sur mes travaux. C'est une erreur. De même, j'aime bien prendre mon temps et réfléchir longuement sur des éléments d'interfaces.
C'est la vue de cette animation de Matt. D. Smith qui me donne envie de me croire webdesigner
Avouez que ce mockup est superbe, son animation hypnotique, promet des lendemains qui chantent, et qu'il est sexy comme une jeune femme aux yeux revolvers qui chevauche un fougueux cabriolet cheveux au vent.
Excusez-moi, je crois que je m'égare. Gare au Garou. Et garons-nous sur le bas-côté.
L'apparition de cette animation date d'un peu après une très forte remise en cause par Apple de son interface mobile iOS. En soit, il y a eu énormément de discussions passionnantes sur ce mockup, à commencer par son auteur qui s'en est expliqué sur son blog. Il y eu aussi de nombreux ports, mais la plupart travaillaient sur un usage peu modéré du javascript. Vous le verrez plus loin pourquoi je pense que ce n'est pas une solution idéale.
État des lieux
Je vais tenter d'appliquer ce principe de formulaire dans l'excellent thème Ductile pour Dotclear qui a la class de la simplicité, l'élégance du responsive, le style de la personnalisation et la french-touch de Kozlika.
Kozlika a fait un superbe travail de design, mais il faut néanmoins reconnaître que le code HTML du formulaire de commentaire de Dotclear n'a pas bougé depuis… 2005. Du moins, dans la version reprise en 2013 pour construire le thème actuel de mon blog.
<form action="#pr" method="post" id="comment-form"> <h3>Ajouter un commentaire</h3> <fieldset> <p class="field"> <label for="c_name">Nom ou pseudo :</label> <input name="c_name" id="c_name" type="text" size="30" value="" /> </p> <p class="field"> <label for="c_mail">Adresse email :</label> <input name="c_mail" id="c_mail" type="text" size="30" value="" /> </p> <p class="field"> <label for="c_site">Site web (facultatif) :</label> <input name="c_site" id="c_site" type="text" size="30" value="" /> </p> <!-- ici, un piège à spam --> <p class="field"> <label for="c_content">Commentaire :</label> <textarea name="c_content" id="c_content" cols="35" rows="7"></textarea> </p> <p class="form-help"> Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées. </p> </fieldset> <fieldset> <p class="buttons"> <input type="submit" class="preview" name="preview" value="prévisualiser" /> </p> </fieldset> </form>
Depuis, on a eu le brouillon WebForms2, son polyfill JS webforms2.js, son implémentation native dans Firefox puis Safari, l'arrivée de Chrome et l'implémentation native dans MSIE. Donc j'ai mis type="email
/url"
, maxlenght="255"
et surtout required
là où ils étaient parfaitement justifié. Vivent les validations côté client.
Ensuite, j'ai transformé le bouton <input type="submit" />
en un réel <button type="submit"></>
, tout en sortant le texte signifiant de la valeur où il n'a rien à faire. Là aussi, les obstacles étaient levés depuis un temps.
Bref, il étant temps de moderniser ce bout de code.
Damnation et implémentation
Je vais essayer de le faire le plus possible sans une once de javascript. Cela peut paraître contradictoire pour un développeur, mais à mon sens,
- plus un code est simple, plus il est parfait ;
- émuler ce que l'on peut faire en natif fait perdre du temps ;
- être au plus proche des standards garanti la pérennité ;
Et surtout que l'Inspecteur Dirty Hacky ne me refasse pas le portrait
Le meilleur exemple que je puisse donner, c'est l'attribut placeholder=""
. Trop peu d'entre vous se souviennent du temps où l'on essayait de créer le comportement placeholder en javascript : Ça plantait, des fois ça merdait quand on cliquait pour mettre . Quand Apple a intégré placeholder
dans le moteur Webkit pour l'application iTunes, on ne se doutait pas que nos calvaires allaient prendre fin.
Bref, il faut voir l'implémentation de ce design de formulaire comme un simple exercice, au même titre que je fais mes kata le matin avec mon kawa. Cette “futilité” doit vous rester en mémoire d'autant plus que depuis la première apparition de cette animation, il existe des bibliothèques javascript (!) qui feront ce boulot. Et qui feront dégainer Dirty Hacky, mais si vous pensez courir plus vite qu'un parseur .357 Magnum, vous pouvez tenter.
Premiers commits dans la Joie !
Toute animation sera en transitions CSS. Sur les plus petits éléments possibles avec le moins possible de repaint/reflow dans le viewport du navigateur afin de garder une belle fluidité d'animation. Parce que là aussi, l'optimisation et la beauté doit passer par l'optimisation des ressources clients.
Dans le mockup, les labels passent en bleu quand le champ a le focus. Une seule solution pour l'implémenter en CSS pur : dans le source html, renverser l'ordre les éléments <label></>
et <input />
.
Première mauvaise surprise : je ne connais aucun sélecteur css pour cibler un élement <input />
ou <textarea></>
tant que son contenu est vide. La pseudo-classe :empty
s'applique à la propriété DOM (el).innerHtml
d'un élément, pas à sa valeur. Cibler en css l'attribut/valeur [value=""]
ne sert à rien. J'ai dû le faire en JS. Bien évidemment, c'est juste une modification de classe, pilotant l'effet graphique en transitions css.
J'ai un autre souci : la pseudo-classe :invalid
s'applique dès le chargement de page, hors je veux changer l'aspect que quand le champ a été changé.
Les pseudo-propriétés propriétaires :-moz-ui-invalid
et :-moz-submit-invalid
seraient parfaites, mais je veux que ça marche sur tous les navigateurs modernes d'un coup sans me prendre la tête et y revenir dessus dans 3 mois. N'oubliez jamais : les préfixes proprios, c'est pas pour mettre en production !
Donc, il me faut écrire un autre polyfill javascript qui mettra au formulaire la class modified
. Ça tient en une dizaine de lignes, mais c'est frustrant.
var tagIfEmpty = '.field'; var markedNotEmpty = 'notEmpty'; var tagIfModified = 'form'; var markedModified = 'modified'; $(tagIfModified).on('change input',tagIfEmpty+' :input',function () { var $p = $(this).closest(tagIfEmpty); if (this.value!=='') { $p.addClass(markedNotEmpty); } else { $p.removeClass(markedNotEmpty); } $p.closest(tagIfModified).addClass(markedModified); });
Oui, le code est ignoble. Et comble de l'insulte, comme j'utilise jQuery depuis un bail sur mon blog, je l'ai pas fait en javascript natif. Honte à Sapajou Hilare.
Bonus d'interface
Il m'a semblé cohérent de n'afficher le bouton d'envoi qu'une fois que le formulaire soit valide, donc quand les champs obligatoires soient remplis et les informations au bon format. Ce qui veut dire que si le site web n'est pas vide, mais que l'url n'est pas valide, le formulaire ne peut être soumis.
Il me manquait aussi un aspect visuel pour indiquer les champs invalides. Plutôt que mettre les champs en rouge, ce qui est trop agressif et impérieux, j'ai tenté avec un léger dégradé sur les champs invalides. C'est peut-être pas le meilleur choix puisque cela casse l'impression d'espace qu'amène les floating labels.
Un message d'information apparaît quand le focus est donné sur au <textarea></>
. Ceux qui commentent régulièrement des blogs ont l'habitude d'avoir soit du BBCode, du Wiki, du MarkUp ou un jeu très restreint de balises HTML. J'estime que c'est inutile (j'en parlerais bientôt) et qu'écrire une adresse web a forcément comme intention de mettre un lien. C'était le comportement par défaut de Dotclear, que j'ai gardé.
Et enfin, quand le bouton de validation apparaît, un texte complémentaire indique si la publication est immédiate ou sujette à validation à priori.
Et voilà !
Vous pouvez tentez la maquette hébergée sur GitHub ou naviguer dans le commit de la version exposée pour ce billet, car je vous parie que l'an prochain, j'aurais complètement refait le vrai formulaire en bas. Ou voir la capture et le code dessous :
HTML : <form action="#pr" method="post" id="comment-form"> <h3>Ajouter un commentaire</h3> <fieldset id="comment-1stline"> <p class="field"> <input name="c_name" id="c_name" maxlength="255" required="required" type="text" placeholder="Nom ou pseudo :" /> <label for="c_name">Nom ou pseudo :</label> </p> <p class="field" id="g_site"> <input name="c_site" id="c_site" maxlength="255" type="url" placeholder="Site web (facultatif) :" /> <label for="c_site">Site web (facultatif) :</label> </p> </fieldset> <fieldset id="comment-2ndline"> <p class="field"> <input name="c_mail" id="c_mail" maxlength="255" required="required" type="email" placeholder="Adresse e-mail :" /> <label for="c_mail">Adresse e-mail :</label> </p> <!-- honeypot --> </fieldset> <fieldset id="comment-3rdline"> <p class="field"> <textarea name="c_content" id="c_content" required="required" placeholder="Commentaire :"></textarea> <label for="c_content">Commentaire :</label> <span class="form-help" id="form-help">Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.</span> </p> </fieldset> <fieldset id="comment-4thline"> <p class="remember"> <button class="preview" name="preview" id="preview" type="submit">prévisualiser</button> <label class="form-help" for="preview">(votre texte sera publié après validation)</label> </p> </fieldset> </form> CSS : .field label { position: absolute; top:0.8em; opacity : 0; transition-property: opacity top; transition-duration: 0.4s; } .field.notEmpty label { top : 0; opacity : 1 ; } .field.notEmpty :active + label, .field.notEmpty :active + label { color : blue; } .field input, .field textarea, .field :active { margin : 0; outline : none; width : 95%; background : transparent; border : none; border-radius: 0px; } .field :invalid { border : none; box-shadow : none; } .modified .field :invalid { background-image: /* préfixes proprios */linear-gradient(top, #EEF 0%, #FFF 30%); } #comment-form p { position : relative; margin : 0; padding : 1em 0 0; border-top : 1px solid #cce ; } #comment-1stline p { border : none; } #comment-1stline #g_site { border-left : 1px solid #cce ; } @media only screen and (em>max-width:479px) { #comment-1stline #g_site { border-top : 1px solid #cce ; border-left : none; } } @media only screen and (min-width:480px) { #comment-1stline .field { float : left; width : 49%; } } #comment-4thline p { padding-top : 0.5em; } #comment-4thline, .modified:invalid #comment-4thlin { opacity : 0; border-top : 1px solid #cce ; transition-property : opacity; transition-duration : 0.4s; } .modified #comment-4thline, .modified:valid #comment-4thline { opacity : 1; } #form-help { display : block; opacity: 0; transition-property: opacity; transition-duration: 0.4s; } textarea:active ~ #form-help { opacity: 1; } #comment-form button { padding : 0.33em 0.66em; border: 1px solid rgb(104, 104, 103); color : rgb(238, 238, 238); font-size : 0.875em; font-weight : bold; text-align : center; text-shadow : 0px 1px 1px rgba(0, 0, 0, 0.3); box-shadow : 0px 1px 2px rgba(0, 0, 0, 0.2); background-image : /* préfixes proprios */linear-gradient(top , rgb(119, 119, 119) 0px, rgb(85, 85, 85) 100%); }
Le débat reste ouvert
Brad Frost a sorti un excellent article critique : Il parle de soucis sur la sémantique, que j'ai tenté d'éviter autant que possible, mais surtout de problèmes d'utilisabilité. Tellement bien raisonné et empli de bon sens que j'avais des doutes à continuer. Notamment, elle oblige au placeholder de porter le même texte que le label, une redondance inutile. Seule la mise en production permet de trancher.
CSS Tricks propose une idée alternative qui enlève la redondance du texte de label, mais la version des labels flottants à droite réduit l'espace utile du champ d'entrée.
Mais surtout, j'ai besoin de votre avis. Vous, mes fidèles lecteurs, laissez un commentaire et dites-moi si vous préférez l'ancien au nouveau formulaire.
11 réactions
1 De pascal - 11/03/2014, 10:05
Salut,
que le placeholder ne soit plus un placehoder me gêne. As tu essayé de placer le label au dessus du champs (avec pointer-events:none et/ou un poil de js pour les tanches) ?
Il m'arrive aussi de placer le label après un input (surtout pour les radio et checkbox pour styler avec [type="radio"]:checked+label et je me pose des questions pour l'accessibilité... (j'ai trouvé des réponses contradictoires, malheureusement c'est souvent le cas dès que l'on veut progresser en a11y...) , ton avis ?
J'ai mis, pour la forme, une adresse email valide (pour le nav et la spec) mais pas valide, pour une personne normale qui souhaiterait vraiment laisser son vrai mail et qui aimerait peut-être que l'on lui signale une erreur sur son adresse... alors Harry regex ou pas sur un champs email ?
2 De Da Scritch - 11/03/2014, 10:38
Hi Pascal !
1- J'avoue, je n'ai pas trop bricolé, justement parce que cela impliquait de faire du JS,ce que je voulais absolument éviter, et surtout que les input, comme tout UI d'un formulaire, peut se retrouver avec un rendu archi-spécifique selon les OS. Après, il y a une mauvaise redondance
placeholder=""
et<label></>
, comme je l'ai décrit dans l'article (que tu n'as visiblement pas totalement lu :P) . Je pense que cela doit être faisable en CSS pur, mais je manque de pratique sérieuse.2- Ça ne pose pas de souci tant que
<label></>
a un attributfor=""
. Ce qui veut dire mettre unid=""
pour chaque<input />
, ce que certains trouvent lourds. L'autre solution est d'inclure le<input />
dans le<label></>
, ce qui est tout aussi valide.3- Il est impossible de valider un e-mail par regex sans avoir de faux-négatifs. Strictement impossible. Après, on peut à la validation faire une recherche sur le nom de domaine en vérifiant qu'il a une entrée MX, mais honnêtement (je l'ai fait pour Simtie), c'est totalement overkill.
Pour terminer, Ultimatom a testé avec de vieux navigateurs (Safari version quelconque, et Firefox 3.6), et évidemment, il fallait que le design du champ fonctionne toujours en dégradation élégante.
3 De pascal - 11/03/2014, 10:52
J'avais bien lu, je donnais juste mon sentiment ;) (pas besoin de (bcp) plus de js... faudrait que je retrouve mon test...)
3. j'avais comme une petite idée de ta réponse ;) ...
4 De test - 11/03/2014, 12:46
teisn
5 De Da Scritch - 11/03/2014, 13:41
Eh ! T'as vu ? Ça marche !
6 De Philippe - 12/03/2014, 08:41
plop
7 De Dsls - 12/03/2014, 09:08
test
8 De Solarus - 12/03/2014, 10:34
Chez moi ça marche. ;)
9 De xylpho - 14/03/2014, 10:22
Je ne dirai rien sur le code ou la démarche technique, bien que la restriction d'usage du JS pour des choses simples soit douce à mon âme.
Je reviendrai dur l'éternel débat de l'organisation des forms de commentaires, tous bâtis sur le même modèle idiot de quasi tous les formulaires, tous à tendance administrative. A savoir, si tu veux dire quelque chose tu dois d'abord donner ton nom, parfois ton prénom, ton site si t'en as un, ton adresse email, la taille de ton sexe et toutes sortes de joyeusetés (je sais, j'exagère mais je fais ce que je veux).
Et enfin, ENFIN, au bout du bout tu peux faire ce pour quoi t'es là, lâcher ton comm'.
Donc c'est joli, design (enfin presque, j'ai du mal avec color: blue et les tailles de police en 9px), mais ça reste un formulaire de commentaire comme les autres.
En dix minutes tu devrais trouver la solution qui consiste à mettre le champs de saisie du commentaire avant les infos de post.
Ne me remercie pas, de toutes façons j'ai raison.
:D
10 De Pierre-Antoine - 12/05/2014, 10:55
Cette solution est super élégante ! Bien mieux qu'un placeholder seul qui pose plusieurs problèmes (ex : oubli de l'information à rentrer pour l'utilisateur, ou pire, quand le premier champ du formulaire à l'autofocus, on sait même pas ce que c'est <-- déjà vu !).
Un petit lien sur l'utilisabilité des placeholders, pour compléter : http://www.nngroup.com/articles/for...
11 De Pierre-Antoine - 12/05/2014, 11:00
Pour faire chier, j'ai désactivé javascript : on retrouve les problèmes du simple placeholder. J'ai même dû effacer un des champs que j'étais entrain de remplir, plus sûr de ce que je devais y mettre. La faute à vouloir entrer les informations trop vite. Enfin, ce n'est jamais la faute de l'utilisateur ;-).
Oups, je dois réactiver javascript pour valider le commentaire ! (natif tu disais ?)