Dispositivo di scorrimento dell'intervallo coerente con il brand

Utilizza l'input dell'intervallo nativo

Utilizza un elemento <input type="range"> con etichetta anziché ricreare un cursore con elementi <div> o gestori di puntatori personalizzati. Il controllo nativo preserva l'interazione con tastiera e puntatore, il comportamento del tocco e il supporto dell'accessibilità. Configura min, max, step e value per il caso d'uso.

<label for="range-slider">Volume</label>
<input type="range" id="range-slider" value="70"/>

Se il valore richiede un'etichetta o un'unità formattata, esponila nei contenuti DOM ordinari e aggiorna aria-valuetext quando viene modificata. Non utilizzare ::before o ::after sugli pseudo-elementi del cursore, poiché i contenuti generati sui controlli dei moduli non sono interoperabili. Se è necessario un tooltip che segue il cursore, ancoralo al cursore con il posizionamento dell'ancoraggio CSS. Consulta Tooltip sensibili alla posizione per i tooltip che mantengono l'orientamento corretto quando vengono capovolti.

Scegli l'approccio di stile

Per una semplice personalizzazione dei colori, utilizza i moduli coerenti con il brand e mantieni il rendering nativo del browser:

input[type="range"] {
  accent-color: var(--brand-color);
}

accent-color non è un'API di stile completa per gli slider. Il suo effetto su cursore, traccia e riempimento dipende dallo user agent. Utilizza gli pseudo-elementi riportati di seguito quando è necessario controllare la barra, il cursore, le dimensioni, la forma o il riempimento.

Definisci lo stile della barra e del cursore

Ripristina lo stile predefinito del sistema operativo con appearance: none, margin: 0 e border: 0. Per normalizzare il rendering tra browser, dichiara gli pseudo-elementi WebKit e Firefox in blocchi di regole separati e centra il cursore WebKit utilizzando margin-block-start: calc((var(--slider-track-size) - var(--slider-thumb-size)) / 2) (Firefox centra automaticamente il cursore). Mantieni i valori rivolti ai consumatori come proprietà personalizzate nell'input, in modo che i temi non abbiano come target direttamente gli pseudo-elementi.

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);
}

Fornisci sempre un indicatore di selezione della tastiera visibile dopo aver rimosso l'aspetto nativo. Non utilizzare solo il colore:

input[type="range"]:focus-visible {
  outline: 2px solid var(--slider-fill-color);
  outline-offset: 4px;
}

Definisci lo stile della traccia attiva

Quando la parte riempita della barra ha uno stile diverso da quello della barra non riempita, Firefox la espone tramite ::-moz-range-progress. WebKit/Blink non forniscono uno pseudo-elemento equivalente, quindi sincronizza il valore di input attivo con --control-value sugli eventi input:

const slider = document.querySelector('#range-slider');

function syncSliderValue() {
  slider.style.setProperty('--control-value', slider.value);
}

syncSliderValue();
slider.addEventListener('input', syncSliderValue);

Limitazioni

  • Non combinare gli pseudo-selettori WebKit e Firefox in un unico elenco separato da virgole (ad es. ::-webkit-slider-thumb, ::-moz-range-thumb); i browser ignorano l'intera regola se viene rilevato uno pseudo-elemento del fornitore non riconosciuto.

Fallback

Alternative e supporto dei browser per accent-color

La proprietà accent-color è un potenziamento progressivo. I browser che non supportano questa proprietà la ignoreranno e utilizzeranno i colori predefiniti della UI.

Alternative e supporto del browser per progress() e attr()

Quando progress() non è supportato, calcola --slider-progress con 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%
    );
  }
}

Quando il tipo attr() non è supportato, sincronizza --attr-min e --attr-max dagli attributi min e max dell'input in 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);
}