Utiliser l'entrée de plage native
Utilisez un <input type="range"> libellé plutôt que de recréer un curseur avec des éléments <div> ou des gestionnaires de pointeurs personnalisés. Le contrôle natif préserve l'interaction avec le clavier et le pointeur, le comportement tactile et la compatibilité avec l'accessibilité. Configurez min, max, step et value pour le cas d'utilisation.
<label for="range-slider">Volume</label>
<input type="range" id="range-slider" value="70"/>
Si la valeur nécessite un libellé ou une unité formatés, exposez-la dans un contenu DOM ordinaire et mettez à jour aria-valuetext en cas de modification. N'utilisez pas ::before ni ::after sur les pseudo-éléments de curseur, car le contenu généré sur les commandes de formulaire n'est pas interopérable. Si une info-bulle qui suit le curseur est requise, ancrez-la au curseur à l'aide du positionnement d'ancrage CSS. Consultez Info-bulles tenant compte de la position pour les info-bulles qui restent correctement orientées lorsqu'elles sont retournées.
Choisir l'approche de style
Pour une personnalisation simple des couleurs, utilisez les formulaires respectant l'identité de la marque et conservez l'affichage natif du navigateur :
input[type="range"] {
accent-color: var(--brand-color);
}
accent-color n'est pas une API complète de style de curseur. Son effet sur le curseur, la piste et le remplissage dépend de l'user-agent. Utilisez les pseudo-éléments ci-dessous lorsque vous devez contrôler la piste, le curseur, les dimensions, la forme ou le remplissage.
Appliquer un style à la piste et au curseur
Réinitialisez le style par défaut de l'OS avec appearance: none, margin: 0 et border: 0. Pour normaliser l'affichage sur différents navigateurs, déclarez les pseudo-éléments WebKit et Firefox dans des blocs de règles distincts, puis centrez le curseur WebKit à l'aide de margin-block-start: calc((var(--slider-track-size) - var(--slider-thumb-size)) / 2) (Firefox centre automatiquement le curseur). Conservez les valeurs en contact avec les clients en tant que propriétés personnalisées sur l'entrée afin que les thèmes ne ciblent pas directement les pseudo-éléments.
input[type="range"] {
--slider-track-size: 0.5rem;
--slider-thumb-size: 1.25rem;
--slider-track-radius: 999px;
--slider-thumb-radius: 50%;
--slider-track-color: #d9d9d9;
--slider-fill-color: #06c;
--slider-thumb-color: var(--slider-fill-color);
--slider-direction: to right;
/* reverse gradient direction for right-to-left layouts */
&:dir(rtl) {
--slider-direction: to left;
}
/* Read min and max from attributes; --control-value is synced by the script below. */
--attr-min: attr(min type(<number>), 0);
--attr-max: attr(max type(<number>), 100);
--control-value: attr(value type(<number>), 50);
--slider-progress: calc(
progress(var(--control-value), var(--attr-min), var(--attr-max)) * 100%
);
appearance: none;
inline-size: 100%;
block-size: 2.5rem; /* Preserve a generous interaction area. */
margin: 0;
padding: 0;
border: 0;
border-radius: 0;
background: transparent;
cursor: pointer;
}
/* WebKit/Blink. */
input[type="range"]::-webkit-slider-runnable-track {
block-size: var(--slider-track-size);
border: 0;
border-radius: var(--slider-track-radius);
background: linear-gradient(
var(--slider-direction),
var(--slider-fill-color) var(--slider-progress),
var(--slider-track-color) var(--slider-progress)
);
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
inline-size: var(--slider-thumb-size);
block-size: var(--slider-thumb-size);
margin-block-start: calc(
(var(--slider-track-size) - var(--slider-thumb-size)) / 2
);
border: 0;
border-radius: var(--slider-thumb-radius);
background: var(--slider-thumb-color);
}
/* Firefox. */
input[type="range"]::-moz-range-track {
block-size: var(--slider-track-size);
border: 0;
border-radius: var(--slider-track-radius);
background: var(--slider-track-color);
}
input[type="range"]::-moz-range-progress {
block-size: var(--slider-track-size);
border-radius: var(--slider-track-radius);
background: var(--slider-fill-color);
}
input[type="range"]::-moz-range-thumb {
inline-size: var(--slider-thumb-size);
block-size: var(--slider-thumb-size);
border: 0;
border-radius: var(--slider-thumb-radius);
background: var(--slider-thumb-color);
}
Fournissez toujours un indicateur de focus clavier visible après avoir supprimé l'apparence native. N'utilisez pas uniquement la couleur :
input[type="range"]:focus-visible {
outline: 2px solid var(--slider-fill-color);
outline-offset: 4px;
}
Appliquer un style à la piste active
Lorsque la partie remplie de la piste est stylisée différemment de la piste non remplie, Firefox l'expose via ::-moz-range-progress. WebKit/Blink ne fournissent pas de pseudo-élément équivalent. Synchronisez donc la valeur d'entrée en direct avec --control-value lors des événements input :
const slider = document.querySelector('#range-slider');
function syncSliderValue() {
slider.style.setProperty('--control-value', slider.value);
}
syncSliderValue();
slider.addEventListener('input', syncSliderValue);
Limites
- Ne combinez pas les pseudo-sélecteurs WebKit et Firefox dans une seule liste d'éléments séparés par une virgule (par exemple,
::-webkit-slider-thumb, ::-moz-range-thumb). Les navigateurs ignorent l'intégralité de la règle s'ils rencontrent un pseudo-élément de fournisseur non reconnu.
Créations de remplacement
Solutions de remplacement et compatibilité des navigateurs pour accent-color
La propriété accent-color est une amélioration progressive.
Les navigateurs qui ne sont pas compatibles avec cette propriété l'ignoreront et utiliseront les couleurs par défaut de leur UI.
Solutions de remplacement et compatibilité des navigateurs pour progress() et attr()
Lorsque progress() n'est pas compatible, calculez --slider-progress avec calc() :
@supports not (opacity: progress(1, 0, 100)) {
input[type="range"] {
--slider-progress: calc(
(var(--control-value) - var(--attr-min)) /
(var(--attr-max) - var(--attr-min)) * 100%
);
}
}
Lorsque le type attr() n'est pas accepté, synchronisez --attr-min et --attr-max à partir des attributs min et max de l'entrée en JavaScript :
function syncSliderValue() {
slider.style.setProperty('--attr-min', slider.min || 0);
slider.style.setProperty('--attr-max', slider.max || 100);
slider.style.setProperty('--control-value', slider.value);
}