Créer un système de masquage/démasquage d’un champ mot de passe

Cet article a 2 années. Il commence à dater, lisez-le donc en gardant son âge en tête ! Merci

L’utilisateur tape son mot-de-passe, et à la fin il doute de ce qu’il a entré sur l’avant dernier caractère. Du coup il retape tout. Et si on lui proposait de démasquer temporairement son mot de passe sur commande ?

Je vois souvent des sites connus proposer des formulaires d’identifications ou des formulaires d’inscription avec un champ « mot de passe » utilisant un type texte. L’effet est assez direct pour moi, on voit mon mot de passe, donc j’envoie un mail à l’équipe qui gère le site pour les prévenir de l’erreur.

« Bonjour Monsieur, ceci n’est pas une erreur et permet à l’internaute de voir ce qu’il a tapé dans le champ. »

Ah ouais carrément ! Ils ont réfléchi en plus, avant de faire cette erreur ?
Bref, sarcasmes mis à part, la personne qui regardera au dessus de votre épaule pendant que vous tapez deux fois votre mot de passe en clair, aura bien le temps de le lire une fois ;)

Concept

Windows 8 propose une gestion du champ mot-de-passe assez interessante puisqu’il permet de masquer et démasquer le code à tout moment avec un bouton placé à droite du champ.
Voilà à quoi ressemble un tel champ :

Champ fourni d'un bouton à droite pour démasquer le mot de passe.

C’est ce comportement que j’ai cherché à reproduire récemment.

Le code

HTML : la structure

Voici un petit morceau de code classique pour la structure HTML :

<div class="connect_box">
   <h1>Connection<span>use your login and password</span></h1>
   <form>
      <p>
         <label for="password">Your password</label>
         <input type="password" value="" placeholder="Enter Password" id="password">
         <button class="unmask" type="button" title="Mask/Unmask password to check content">Unmask</button>
      </p>
   </form>
</div>

Je ne pense pas que vous ayez besoin d’explications, mais si c’était le cas laissez-moi un petit commentaire en fin d’article.
Le bouton est présent uniquement pour intercepter l’action de masquage et démasquage, mais vous allez comprendre par vous-même. Je n’ai pas mis de bouton submit pour alléger le code :)

CSS : les styles

Un peu de mise en forme avec CSS, rien de sorcier également, nous verrons le design du bouton de démasquage plus tard :

div {
  width: 400px;
  margin: 0 auto;
  text-align: center;
}
h1 {
  font-size: 30px;
  color: #969696;
  text-shadow: 1px 1px 0px #fff;
  font-weight: 100;
}
 h1 span {
  display:block;
  font-size: 14px;
  color: #bbb;
 }
form p { position: relative; }
label { 
  position:absolute;
  left:-9999px;
  text-indent: -9999px;
}
input {
  width: 250px;
  padding: 10px 12px;
  margin-bottom: 5px;
  border: 1px solid #cccccc;
  border-bottom-color: #fff;
  border-right-color: #fff;
  border-radius: 4px;
  background: #e3e3e3;
  color: #888;
}

Voici la partie concernant le petit bouton. J’ai souhaité faire quelque chose en full CSS sans image, mais à vous d’adapter la chose.


.password + .unmask {
  position:absolute;
  right: 68px; top: 7px;
  width: 25px;
  height: 25px;
  text-indent: -9999px;
  background: #aaa;
  border-radius: 50%;
}
.password + .unmask:before {
  content: "";
  position:absolute;
  top:4px; left:4px;
  z-index:1;
  width: 17px;
  height: 17px;
  background: #e3e3e3;
  border-radius: 50%;
}
.password[type="text"] + .unmask:after {
  content: "";
  position:absolute;
  top:6px; left:6px
  z-index:2;
  width: 13px;
  height: 13px;
  background: #aaa;
  border-radius: 50%;
}

On donne une forme ronde à notre bouton, puis on lui change légèrement son aspect lorsque le champ password devient un champ de type text. Pour effectuer le passage de l’un à l’autre, on va utiliser JavaScript.

JavaScript : les actions

Là où ça fait vraiment mal, c’est la fonction JavaScript.
Je pensais utiliser simplement jQuery pour changer la valeur de l’attribut type et la faire passer de password à text.
C’est un peu la base de la technique, et sur le principe c’est hyper simple.

Sauf que ça ne se passe pas comme ça : l’accès à l’attribut type est « interdit ».
Il va falloir en quelque sorte récupérer l’élément, chacun de ses attributs et ses valeurs, puis recréer un nouvel élément composé des mêmes attributs (on en profitera pour changer la valeur du type ;) ) pour l’insérer dans le DOM.

Je vais donc vous donner la partie facile du code, celle qui consiste à dire à l’élément « change de type quand on clique là-dessus ». Je vous donne la fonction plus complexe juste après.

$('.unmask').on('click', function(){
  
  if($(this).prev('input').attr('type') == 'password')
    changeType($(this).prev('input'), 'text');
  
  else
    changeType($(this).prev('input'), 'password');
  
  return false;
});

Le code fait la chose suivante : au clic, si l’input précédent le bouton est de type password, alors il passe en type text ; s’il est de type text, il repasse en password.

La fonction changeType() est définie ainsi :

/* 
  function from : https://gist.github.com/3559343
  Thank you bminer!
*/
// x = élément du DOM, type = nouveau type à attribuer
function changeType(x, type) {
   if(x.prop('type') == type)
      return x; // ça serait facile.
   try {
      // Une sécurité d'IE empêche ceci
      return x.prop('type', type);
   } 
   catch(e) {
      // On tente de recréer l'élément
      // En créant d'abord une div
      var html = $("<div>").append(x.clone()).html();
      var regex = /type=(\")?([^\"\s]+)(\")?/;
      // la regex trouve type=text ou type="text"
      // si on ne trouve rien, on ajoute le type à la fin, sinon on le remplace
      var tmp = $(html.match(regex) == null ?
         html.replace(">", ' type="' + type + '">') :
         html.replace(regex, 'type="' + type + '"') );

      // on rajoute les vieilles données de l'élément
      tmp.data('type', x.data('type') );
      var events = x.data('events');
      var cb = function(events) {
         return function() {
            //Bind all prior events
            for(i in events) {
               var y = events[i];
               for(j in y) tmp.bind(i, y[j].handler);
            }
         }
      }(events);
      x.replaceWith(tmp);
      setTimeout(cb, 10); // On attend un peu avant d'appeler la fonction
      return tmp;
   }
}

Limites

Mon exemple utilise CSS3. Pour une meilleure prise en charge de l’aspect du bouton, utilisez le principe de dégradation gracieuse en prévoyant une image pour les vieux navigateurs, par exemple.

IE7 et 8 ne reconnaissant pas la validité de la première partie du code JS (la partie « try »), le reste du code permet le changement de type, mais l’information entrée dans le champ de type password est indépendante de l’information entrée dans le champ une fois passé en type text.

Pour ceux qui veulent forker le code :
Le code sur CodePen.io

3 commentaires sur “Créer un système de masquage/démasquage d’un champ mot de passe”

  1. Twikito dit :
    3 décembre 2012

    De quelle manière tu as pu voir que l’accès à l’attribut type était « interdit » ?

    • Geoffrey dit :
      3 décembre 2012

      jQuery semblait empêcher un simple changement de type à mon dernier essai. La doc sur MSDN en parle également (mais c’est bien caché) :
      http://msdn.microsoft.com/en-us/library/ie/ms534700%28v=vs.85%29.aspx
      Je me souviens avoir eu un problème de ce genre sur un script plus complexe où j’avais dû coder une magnifique boucle pour recréer les éléments dans le DOM (jeux de checkboxes), enfin, c’est une autre histoire, mais IE n’aime pas trop qu’on modifie des choses à la volée dans les champs de formulaire on dirait.

  2. 24 décembre 2012

    Salut Geoffrey,

    Un super article, je pense que c’est une best-practice de proposer d’afficher le mot de passe tappé dans les formulaires.
    Je viens de remarquer que le framework metroui.css le propose aussi, as-tu jeté un coup d’œil dessus ? http://metroui.org.ua/forms.php

    Passes de bonnes fêtes :)

Laisser un commentaire

Certains codes HTML ne sont pas échappés automatiquement. Pour afficher du code dans votre commentaire, merci d'échapper vos chevrons en utilisant "&lt;" et "&gt;" en lieu et place de "<"" et ">".

Il est difficile de proposer un support pour tous les articles de ce blog. En ne fournissant pas un moyen de consulter votre code bogué, vous vous assurez de ne pas avoir de réponse adaptée. Utilisez CodePen.io à défaut d'une page web.

 
Le studio web