aller au contenu principal

Personnaliser l'apparence d'un input de type range en CSS

Avec des prĂ©fixes CSS (pas bien 😱)


Publié le 08/02/2024 dans BlogMis à jour le 10/02/2024
Crédit photo - Unsplash - Tina WitherspoonCrédit photo : Unsplash - Tina Witherspoon
Je suis en train d'Ă©crire un cours complet sur Flexbox. Il y aura un module entier sur la comprĂ©hension de ce mode de layout, et un module 100% pratique avec plusieurs exercices.Tu peux consulter le programme et Ă  te prĂ©inscrire dĂšs maintenant ! âŹ‡ïžSe prĂ©inscrire

⚠ Avant de commencer, je tiens Ă  prĂ©ciser que cet article montre des exemples d'utilisation de prĂ©fixes CSS (non standard). Il faut ĂȘtre prudent lors de l'utilisation de ces prĂ©fixes car ils ne sont pas standardisĂ©s et peuvent changer Ă  tout moment. Il est prĂ©fĂ©rable de les utiliser avec parcimonie et de les retirer dĂšs que possible.

Dans un précédent article, nous avons exploré les possibilités de personnalisation CSS sur l'input de type file.

Je te propose maintenant de s'attaquer Ă  un autre input : l'input de type range.

Le CSS offre également un bon niveau de personnalisation pour cet élément, grùce à l'utilisation de préfixes CSS qui assurent une apparence uniforme sur différents navigateurs.


L'apparence par défaut

Commençons par analyser l'apparence par défaut de l'input de type range, pour cela il suffit de le créer en HTML :

<input type="range" />

En fonction du navigateur, l'apparence de l'input de type range est bien différente :

L'apparence par défaut d'un input de type range sur les différents navigateurs (Chrome, Forefox, Safari et Edge)

Les largeurs ne sont pas les mĂȘmes, les hauteurs non plus, et les couleurs non plus (ça fait beaucoup de diffĂ©rences 😅).

Heureusement, le CSS permet de prendre le contrĂŽle de tout cela.

Mais avant, je te propose de comprendre de quoi est composé un input de type range.

Anatomie d'un input de type range

Deux éléments composent un input de type range :

  • l'input track qui est la barre sur laquelle on fait glisser l'input thumb
  • l'input thumb qui est le curseur que l'on fait glisser sur l'input track

L'input de type range est donc la combinaison de ces deux éléments.

Il faudra donc cibler en CSS ces deux éléments pour pouvoir les styliser.

Un input de type range est composé de deux éléments : un input track et un input thumb

Styliser l'input de type range avec accent-color ?

Il est possible d'utiliser une propriété encore relativement nouvelle et trÚs bien supportée pour styliser l'input de type range : la propriété CSS accent-color.

Pour rappel : cette propriété permet de changer la couleur d'accentuation, si elle existe, d'un élément de formulaire.

Si tu regardes la premiÚre image de cet article, tu remarqueras que l'input a une couleur d'accentuation différente en fonction du navigateur : bleu sur Chrome et Firefox, grise sur Edge, et sans couleur sur Safari.

Essayons d'utiliser cette propriété pour voir ce que ça donne :

input[type="range"] {
  accent-color: red;
}

Une seule ligne de CSS permet d'obtenir ce résultat :

Utilisation de la propriété CSS accent-color sur un input de type range

Cette propriété fonctionne trÚs bien et elle est trÚs rapide à mettre en place, mais elle ne permet pas de prendre le contrÎle complet de l'apparence de l'input de type range, ce n'est pas son rÎle.

On peut d'ailleurs observer qu'elle n'a pas d'effet sur Safari (macOS).

Aussi, sur Firefox elle ne permet pas de changer la couleur de l'input thumb qui reste gris.

On ne conservera donc pas cette propriĂ©tĂ© dans la suite de l'article. Si on veut la mĂȘme apparence sur nos inpits, il faut styliser l'input track et l'input thumb.

La propriĂ©tĂ© accent-color est une bonne option pour avoir des Ă©lĂ©ments de formulaire aux couleurs de ton choix, tout en gardant l'apparence proposĂ©e par les navigateurs (cela peut ĂȘtre une volontĂ© de garder ces apparences par dĂ©faut).

Retirer l'apparence par défaut

Avant de pouvoir styliser l'input de type range, il faut retirer son apparence par défaut, en faisant un reset en quelque sorte.

Pourquoi faire cela ? Car sinon on ne pourra pas le styliser, certaines propriétés CSS n'auront tout simplement aucun effet.

C'est le cas de la propriété height ou de background-color qui ne fonctionneront pas si au préalable l'apparence par défaut n'est pas retirée.

Il existe une propriété CSS pour cela, c'est la propriété appearance, sur laquelle on va venir mettre la valeur none :

input[type="range"] {
  appearance: none;
}

Faire cela aura un impact sur l'input lui mĂȘme, mais aussi sur l'input track en retirant certains styles par dĂ©faut comme l'arrondi des coins, le degradĂ© sur Safari, etc.

Ce que tu ne verras pas si tu observes l'input sur un fond blanc, c'est que l'input lui mĂȘme a un fond blanc :

Attention : ce n'est pas l'input track qui a un fond blanc, mais l'input lui mĂȘme.

Donc sur un fond autre que blanc cela se voit :

L'input de type range a un fond blanc par défaut

Mettons donc un background: transparent sur l'input pour régler cela :

input[type="range"] {
  appearance: none;
  background: transparent;
}

Les largeurs restent sensiblement différentes, on peut donc les harmoniser.

On peut mettre également un cursor: pointer pour améliorer le retour visuel au survol de l'input :

input[type="range"] {
  appearance: none;
  background: transparent;
  width: 15rem;
  cursor: pointer;
}

Les hauteurs ne sont pas les mĂȘmes non plus, mais on harmonisera cela avec l'input track en lui donnant une hauteur.

Styliser l'input track

C'est à partir de maintenant que nos inputs vont commencer à se ressembler, car pour le moment, leurs apparences sont encore bien différentes.

Pour styliser l'input track, nous allons nous servir des pseudo-éléments ::-webkit-slider-runnable-track et ::-moz-range-track.

Le premier est pour les navigateurs Chromium (Chrome, Safari, Edge (Chromium)), le second pour Firefox.

Modifions la hauteur, la couleur de fond (on peut mĂȘme mettre un dĂ©gradĂ© đŸ€©) et ajoutons des arrondis sur l'input track :

/* Chrome, Safari, Edge (Chromium) */
input[type="range"]::-webkit-slider-runnable-track {
  background: linear-gradient(to right, red 0%, #053a5f 50%, blue 100%);
  height: 0.5rem;
  border-radius: 3px;
}

/* Firefox */
input[type="range"]::-moz-range-track {
  background: linear-gradient(to right, red 0%, #053a5f 50%, blue 100%);
  height: 0.5rem;
  border-radius: 3px;
}

Tu noteras qu'il n'est pas nécessaire de mettre un appearance: none sur ces pseudo-éléments.

Comme tu peux le voir, changer la hauteur de l'input track va provoquer un problĂšme de positionnement sur l'input thumb, mais seulement sur les navigateurs Chromium : Chrome, Safari, et Edge.

Firefox est le seul qui n'a pas ce problĂšme :

Changer la hauteur de l'input track va créer un problÚme de positionnement (sauf sur Firefox)

Pour régler ce problÚme il faut cibler l'input thumb.

Styliser l'input thumb

Comme on l'a vu précédemment, l'input thumb est le curseur que l'on fait glisser sur l'input track.

Pour cet élément aussi, il y a deux pseudo-éléments pour le styliser : ::-webkit-slider-thumb et ::-moz-range-thumb.

Contrairement Ă  l'input track, il faudra ici lui mettre un appearance: none pour pouvoir le styliser.

Aussi par dĂ©faut sur Firefox, le thumb Ă  des bords arrondis, et ça mĂȘme aprĂšs le appearance: none.

Il faut donc soit les enlever, soit les rajouter pour les navigateurs Chromium :

/* Chrome, Safari, Edge (Chromium) */
input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  background: #0075FF;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
}

/* Firefox */
input[type="range"]::-moz-range-thumb {
  appearance: none;
  background: #0075FF;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
}

Pourquoi ne pas regrouper les styles des deux pseudo-Ă©lĂ©ments en une seule rĂšgle, puisque ce sont les mĂȘmes propriĂ©tĂ©s ? đŸ€”

C'est une bonne question ! 😉

La raison est trÚs simple : si un sélecteur n'est pas compris par un navigateur, alors il doit l'ignorer.

Si on prend l'exemple du navigateur Firefox, il ne comprend pas le sélecteur ::-webkit-slider-thumb, il doit donc ignorer tout le sélecteur, c'est pour cette raison que l'on ne peut pas grouper les deux pseudo-éléments.

Il faut maintenant centrer l'input thumb sur l'input track, mais uniquement pour les navigateurs Chromium :

Changer la hauteur de l'input track va créer un problÚme de positionnement (sauf sur Firefox)

Nous allons utiliser pour cela la propriété margin-top en mettant une valeur négative.

La formule est la suivante : margin-top = (hauteur du l'input track en pixel / 2) - (hauteur de l'input thumb en pixel / 2).

Pour rappel, il ne faut faire cela que pour les navigateurs Chromium, donc uniquement sur le pseudo-élément ::-webkit-slider-thumb.

Ajoutons des variables CSS pour rendre le code plus maintenable :

:root {
  --track-height: 6px;
  --thumb-height: 12px;
  --thumb-width: 12px;
}

/* Chrome, Safari, Edge (Chromium) */
input[type="range"]::-webkit-slider-thumb {
  width: var(--thumb-width);
  height: var(--thumb-height);
  margin-top: calc((var(--track-height) / 2) - (var(--thumb-height) / 2));
}

Il subsiste une différence sur Firefox, l'input thumb a une bordure grise :

Sur Firefox, l'input thumb a une bordure grise

Il faut donc au choix :

  • retirer la bordure
  • styliser la bordure

Choisissons la deuxiÚme option en mettant sur l'input thumb un fond blanc et une bordure colorée :

/* Chrome, Safari, Edge (Chromium) */
input[type="range"]::-webkit-slider-thumb {
  background: #fff;
  border: 3px solid #3353fe;
}

/* Firefox */
input[type="range"]::-moz-range-thumb {
  background: #fff;
  border: 3px solid #3353fe;
}

Voici le code complet de ce qui a été réalisé jusqu'à présent :

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="/styles.css" />
  </head>

  <body>
    <input type="range" />
  </body>

</html>

Comme tu peux le voir, les inputs ont dĂ©sormais une apparence identique sur les diffĂ©rents navigateurs 😎 :

Exemple d'input de type range sur plusieurs navigateurs avec une apparence identique

Améliorer le focus

Comme tous les éléments de formulaire, ces derniers ont un focus par défaut, celui proposé par le navigateur.

Ce focus a lui aussi une apparence différente en fonction du navigateur.

Retirer le focus par défaut

Parce qu'il est diffĂ©rent sur les diffĂ©rents navigateurs, il est prĂ©fĂ©rable de le retirer pour ensuite le styliser nous mĂȘme ! 😎

On peut noter que sur Safari il n'y a pas de focus par défaut sur l'input de type range (c'est aussi le cas sur les balises <button>) :

Exemple d'input de type range avec un focus

Pour retirer le focus d'un élément, il suffit d'utiliser la propriété outline en lui mettant la valeur none :

input[type="range"]:focus {
  outline: none;
}

Styliser le focus

On ne va pas styliser le focus de l'input, mais plutĂŽt celui de l'input thumb, car je trouve que cela a plus de sens. AprĂšs tout, c'est cet Ă©lĂ©ment que l'utilisateur dĂ©place, pas l'input lui-mĂȘme :

/* On retire le focus par défaut sur l'input */
input[type="range"]:focus {
  outline: none;
}

/* Chrome, Safari, Edge (Chromium) */
input[type="range"]:focus::-webkit-slider-thumb  {
  outline: 2px solid #3353fe;
  outline-offset: 2px;
}

/* Firefox */
input[type="range"]:focus::-moz-range-thumb {
  outline: 2px solid #3353fe;
  outline-offset: 2px;
}

Voici le résultat final :

Exemple d'input de type range avec un focus sur l'input thumb

Le code complet :

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="/styles.css" />
  </head>

  <body>
    <input type="range" />
  </body>

</html>

Je te remercie de m'avoir lu, n'hésites pas à me donner ton avis sur cet article sur Twitter !

Si tu souhaites ĂȘtre prĂ©venu de la sortie des prochains articles et contenu du site, tu trouveras le formulaire d'inscription Ă  ma newsletter un peu plus bas.

À bientĂŽt, Seb đŸ€˜

2024 SĂ©bastien Imbert