[CSS]Personnalisation des <input type="range">

NoSmoking

Parmi les nouveautés apparues avec HTML5, et à partir de la version 10 pour IE, il en est une qui présente un aspect très différent suivant les navigateurs, j'ai nommé l'<input type="range">.

Aucun accord, même lointain, n'ayant été trouvé et si l'on souhaite obtenir un rendu identique sur les différents navigateurs il n'est pas d'autres moyens que de reprendre les styles de base.

Modifier les styles de ces éléments est tout à fait réalisable et nous allons voir comment.

Etat existant

Rendu par défaut des navigateurs

rendu par défaut

Rendu par défaut du navigateur

<input type="range" value="50">

Quelques explications

On distingue deux éléments principaux sur les <input type="range">, le curseur (thumb) et la zone sur laquelle il se déplace (track).

Les éléments « track » et « thumb » sont des pseudo-éléments ajoutés au <input> dont le style dépend des navigateurs.

Leur style peut être modifié en utilisant dans les sélecteurs les pseudo-éléments propriétaires suivant :

Pour la zone de déplacement (track) :

Pour le curseur (thumb) :

On notera qu'il existe d'autres pseudo-éléments dont la liste diffère suivant les navigateurs.

Elément personnalisé

<input class="custom-slider" type="range" value="50">

Bon d'accord ce n'est pas très fun mais le rendu sera le même.

Modification du CSS

/* partie commune */
input[type=range].custom-slider {
  -webkit-appearance: none;     /*nécessaire pour Chrome */
  padding: 0;                   /* nécessaire pour IE */
  font: inherit;                /* même rendu suivant font document */
  outline: none;
  color: #069;                  /* sert pour couleur de référence, via currentColor, pour le curseur */
  opacity: .8;
  background: #CCC;             /* sert pour couleur de fond de la zone de déplacement */
  box-sizing: border-box;       /* même modèle de boîte pour tous */
  transition: opacity .2s;
  cursor: pointer;
}

Pour se faciliter la vie, on fixe une couleur, ici color: #069, afin d'utiliser par la suite la valeur currentColor.

Cette simple règle ne suffit pas pour obtenir un rendu identique sur les différents navigateurs. Il nous faut également faire un « reset » sur les pseudo-éléments.

Lors de l'analyse d'une règle CSS, si un sélecteur n'est pas valide c'est le bloc de déclaration tout entier qui est ignoré, c'est pour cette raison que l'on ne peut pas regrouper les sélecteurs en présence de préfixes propriétaires et qu'il faut donc dupliquer les règles.

Vous pouvez bien évidement utiliser des préprocesseurs CSS comme SASS ou encore LESS, il en existe d'autres, pour vous simplifier la tâche.

Chrome

/* la zone de déplacement */
input[type=range].custom-slider::-webkit-slider-runnable-track {
  height: 100%;
  border: none;
  border-radius: 0;
  background-color: transparent;  /* supprimé définie sur l'input */
}
/* le curseur */
input[type=range].custom-slider::-webkit-slider-thumb {
  -webkit-appearance: none;       /* également nécessaire sur le curseur */
  width: 1em;
  height: inherit;                /* s'adapte à la hauteur de l'input */
  border: none;
  border-radius: 0;               /* pris en compte sur Webkit et Edge */
  background: currentColor;       /* pris en compte sur Webkit only */
}

Firefox

/* la zone de déplacement */
input[type=range].custom-slider::-moz-range-track {
  height: 100%;
  border: none;
  border-radius: 0;
  background-color: transparent;  /* supprimé définie sur l'input */
}
/* le curseur */
input[type=range].custom-slider::-moz-range-thumb {
  width: 1em;
  height: inherit;                /* s'adapte à la hauteur de l'input */
  border: none;                   /* supprimer la bordure */
  border-radius: 0;               /* supprimer le rayon */
  background: currentColor;
}
/* barre progression avant */
input[type=range].custom-slider::-moz-range-progress {
  height: 0;
  background: transparent;        /* supprime barre progression avant */
}

IE, Egde

/* la zone de déplacement */
input[type=range].custom-slider::-ms-track {
  height: 100%;
  border: none;
  border-radius: 0;
  color: transparent;             /* supprime les graduations pour IE */
  background-color: transparent;  /* supprimé définie sur l'input */
}
/* le curseur */
input[type=range].custom-slider::-ms-thumb {
  width: 1em;
  height: inherit;                /* s'adapte à la hauteur de l'input */
  border: none;                   /* supprimer la bordure */
  border-radius: 0;               /* supprimer le rayon */
  background: currentColor;
}
/* la tooltip de la valeur */
input[type=range].custom-slider::-ms-tooltip {
  display: none;                  /* supprime l'affichage de la valeur au survol */
}
/* barre progression avant */
input[type=range].custom-slider::-ms-fill-lower {
  background: transparent;
}
/* barre progression après */
input[type=range].custom-slider::-ms-fill-upper {
  background: transparent;
}

En mettant sur le curseur la déclaration height:inherit, celui-ci prendra la hauteur de l'input, mais il faudra quand même ajuster la width.

Certaines propriétés ne sont pas concernées mais reprises pour conserver l'homogénéité des déclarations et du fait qu'Edge utilise également le préfixe propriétaire -webkit-.

A ce sujet il peut-être nécessaire de placer les déclarations -webkit- avant les déclarations -ms-.

Un peu plus de style

Voici ce que l'on peut réaliser simplement :

<input class="custom-slider custom-slider-bullet" type="range">

Bien que tous les goûts et les couleurs soient dans la nature il y a quand même du mieux non ?

La partie style modifiée pour obtenir ce résultat est la suivante :

/*==============================*/
/* partie commune               */
/*==============================*/
input[type=range].custom-slider.custom-slider-bullet {
  height: 2em;
  color: #FFF;
  background: transparent;
  background-image: linear-gradient(to bottom, #FFF, #999, #FFF);
  background-position: center;
  background-repeat: no-repeat;
  background-size: 100% 25%;
}
/*==============================*/
/* le curseur                   */
/*==============================*/
input[type=range].custom-slider.custom-slider-bullet::-webkit-slider-thumb {
  width: 2em;
  padding: 0.25em;                                              /* largeur du bord */
  border: 1px solid #888;
  border-radius: 50%;
  box-shadow: 0 0 .5em #FFF inset;
  background: linear-gradient(#888, #FFF) content-box,          /* le centre */
              linear-gradient(-90deg, #888, #DDD) border-box;   /* le bord */
}
input[type=range].custom-slider.custom-slider-bullet::-moz-range-thumb {
  width: 2em;
  padding: 0.25em;                                              /* largeur du bord */
  border: 1px solid #888;
  border-radius: 50%;
  box-shadow: 0 0 .5em #FFF inset;
  background: linear-gradient(#888, #FFF) content-box,          /* le centre */
              linear-gradient(-90deg, #888, #DDD) border-box;   /* le bord */
}
input[type=range].custom-slider.custom-slider-bullet::-ms-thumb {
  width: 2em;
  padding: 0.25em;                                              /* largeur du bord */
  border: 1px solid #888;
  border-radius: 50%;
  box-shadow: 0 0 .5em #FFF inset;
  background: linear-gradient(#888, #FFF) content-box,          /* le centre */
              linear-gradient(-90deg, #888, #DDD) border-box;   /* le bord */
}

On peut noter que tous les blocs de déclaration sont identiques, il suffit donc de faire un copier/coller.

Sur IE-Edge le curseur ne pouvant pas déborder de la zone de déplacement on a joué avec la hauteur de l'<input>, d'autres techniques peuvent être mise en oeuvre.

Les modifications apportées concernent essentiellement le curseur et sont les mêmes pour tous, l'utilisation des variables CSS pourrait permettre de maintenir plus facilement la feuille de style.

La zone de déplacement est stylée au travers de la propriété background de l'<input>.

Conclusion

Voilà une approche simple pour modifier les <input type="range">, vous pouvez toujours vous rabattre sur les nombreuses sources javascript ou « plugins » existants, voire créer vos propres « sliders », mais il serait dommage de se priver de ce qui existe en natif sur les navigateurs qui à l'aide d'un peu de CSS peuvent être visuellement très sympathique.

Ressources