Dans ce tutoriel je vous propose de découvrir comment créer des champs de textes inspirté du style Material Design. Le principe est de jouer avec le label pour le transformer en placehodler suivant les cas.

Le code HTML

L'objectif est de ne pas affecter notre code HTML pour des besoins de style, donc nous allons garder un code HTML à son strict minimum.

<div class="field">
    <label for="doge" class="field-label">Label text</label>
    <input type="text" id="doge" name="doge" class="field-input">
</div>

Pour styliser plus simplement j'ai pris l'habitude de mettre une classe sur chaque élément.

Le CSS

Pour la suite, je n'utiliserai pas les prefixes CSS pour garder le code le plus clair possible, mais n'hésitez pas à passer un coup d'autoprefixer à la fin. De la même façon mes éléments ont un box-sizing: border-box;

On va commencer par styliser le conteneur .field en respectant les dimensions préconisées par google

.field{
   position: relative;
   height: 72px;
   padding: 16px 0 8px 0;
}

Pour le label, on va le placer normalement, puis utiliser les tranformations CSS pour le transformer en placeholder.

.field-label{
   position: relative;
   margin: 0;
   display: block;

   color:  #bfbfbf;
   line-height: 16px;
   font-size: 16px;
   font-weight: 400;

   transform: translateY(24px);
   transition: transform 0.3s, color 0.3s;
   transform-origin: 0 50%;
}

Enfin, on va rendre le champs invisible en supprimant le fond et les bordures.

.field-input{
   position: relative;
   display: block;
   width: 100%;
   height: 32px;
   padding: 8px 0;

   line-height: 16px;
   font-family: Roboto;
   font-size: 16px;

   background: transparent;
   border: none;
   -webkit-appearance: none;
   outline: none;
}

Enfin, pour créer la bordure sous le champs nous utiliserons les pseudo-éléments. On pourrait créer une bordure sur le champs mais vu que l'on souhaite animer la barre, un pseudo-élément est plus intéréssant.

.field::after, .field::before{
   content:'';
   height: 2px;
   width: 100%;
   position: absolute;
   bottom: 6px;
   left: 0;

   background-color: #e6e6e6;
}

.field::after{
   background-color: $color;
   transform: scaleX(0);
   transition: transform 0.3s;
}

On va ensuite devoir gérer 2 cas, gràce à des classes CSS

  • has-label, lorsque le champs le label doit être visible
  • is-focused, lorsque le champs est actif
.has-label .field-label{
   transform: translateY(0) scale(0.75);
}

.is-focused .field-label{
   color: $color;
}
.field.is-focused::after{
   transform: scaleX(1);
}

Une surcouche de JS

Malheureusement il n'est pas possible de gérer les différents états avec seulement du CSS, du coup on va rajouter une petite surcouche de javascript pour gérer l'ajout de classes HTML.

jQuery(function($) {
  //  Au focus
  $('.field-input').focus(function(){
    $(this).parent().addClass('is-focused has-label');
  });

  // à la perte du focus
  $('.field-input').blur(function(){
    $parent = $(this).parent();
    if($(this).val() == ''){
      $parent.removeClass('has-label');
    }
    $parent.removeClass('is-focused');
  });

  // si un champs est rempli on rajoute directement la class has-label
  $('.field-input').each(function(){
    if($(this).val() != ''){
      $(this).parent().addClass('has-label');
    }
  });

})

On pourrait se passer aisément de jQuery ici, mais on va pas se compliquer la vie (#fainéant). Vu que les animations sont gérées en CSS le code ne consiste qu'à l'ajout/suppression de classes.

Pour aller plus loin

Le but de ce tutoriel est de reproduire au plus proche l'effet présent sur android mais on peut imaginer un tas de styles différents. N'hésitez pas à faire un tour sur coddrops pour vous inspirer.