Range-Input optisch gestalten: Slider ohne JavaScript-Bibliothek
AI generated
{ }
@
CSS · Formulare · Range-Slider · Barrierefreiheit
Range-Input optisch gestalten
Track, Thumb und Fuellstand ohne schwere JS-Bibliothek

Ein Range-Input gehoert zu den Formularelementen mit den groessten Unterschieden zwischen Browsern, weil Track, Thumb und Fuellstand jeweils eigene, herstellerspezifische Selektoren benoetigen. Mit den richtigen CSS-Techniken laesst sich ein vollstaendig individueller Slider bauen, ohne eine zusaetzliche JavaScript-Bibliothek einzubinden.

18 Min. Lesezeit input range · Track · Thumb · datalist · Custom Properties Chrome · Firefox · Safari · Edge

1. Warum Range-Slider so schwer konsistent zu stylen sind

Ein Range-Slider besteht optisch aus drei Teilen, die alle unterschiedlich gestylt werden muessen: dem Track als Hintergrundspur, dem Thumb als beweglichem Griff, und dem gefuellten Bereich zwischen dem linken Rand und dem Thumb. Kein Browser bietet fuer alle drei Teile identische, praefixfreie Selektoren, und das Standardverhalten unterscheidet sich in Details wie der vertikalen Zentrierung des Thumbs oder der Existenz eines separaten gefuellten Bereichs.

Firefox rendert den gefuellten Bereich eines Range-Sliders automatisch mit einer eigenen Farbe ueber ::-moz-range-progress, waehrend Chrome und Safari diesen Bereich traditionell nicht separat anbieten und stattdessen einen Trick mit background und einem linear-gradient erfordern. Diese fundamentalen Unterschiede sind der Hauptgrund, warum ein Range-Input mit konsistentem Fuellstand in allen Browsern eine der anspruchsvolleren CSS-Aufgaben im Formularbereich bleibt, auch wenn accent-color, wie in einem anderen Artikel dieser Serie beschrieben, fuer einfache Faelle bereits ausreicht.

2. Basis-Reset: appearance none auf Input und Thumb

Der erste Schritt bei jedem individuell gestalteten Range-Input ist ein vollstaendiger Reset der nativen Darstellung, sowohl auf dem input-Element selbst als auch auf beiden herstellerspezifischen Thumb-Pseudo-Elementen. Ohne diesen Reset ueberlagert die native Spur-Grafik jede eigene Hintergrundfarbe, und der native Thumb behaelt seine systemtypische Form, unabhaengig von den nachfolgenden CSS-Regeln.

Ein haeufiger Anfaengerfehler: Nur appearance: none auf das input-Element zu setzen und die Thumb-Pseudo-Elemente zu vergessen. Der Track verschwindet dann zwar, aber der native Thumb bleibt in seiner Originalform bestehen, was zu einem visuell inkonsistenten Ergebnis fuehrt, bei dem der eigene Track auf einen fremden, unpassenden Thumb trifft. Beide Ebenen, Input und Thumb, muessen konsequent zurueckgesetzt werden.


/* Full reset, applies to the track element itself */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  background: transparent;
  cursor: pointer;
}

/* Firefox draws its own focus outline around the whole element by default */
input[type="range"]::-moz-focus-outer {
  border: 0;
}

3. Track gestalten: Hoehe, Radius, Grundfarbe

Nach dem Reset uebernimmt ::-webkit-slider-runnable-track in WebKit- und Blink-Browsern sowie ::-moz-range-track in Firefox die Gestaltung der Hintergrundspur. Beide Pseudo-Elemente akzeptieren Hoehe, Radius und Hintergrundfarbe wie ein gewoehnliches Block-Element, muessen aber wie beim Thumb in getrennten Selektorlisten definiert werden, weil ein unbekannter Selektor sonst die komplette Regel ungueltig macht.

Ein Detail, das beim Range-Input oft uebersehen wird: Die Track-Hoehe in Firefox und WebKit reagiert unterschiedlich auf die Gesamt-Hoehe des input-Elements. Deshalb empfiehlt es sich, die Hoehe konsequent am Track-Pseudo-Element selbst zu definieren, statt sich auf die Hoehe des umschliessenden Inputs zu verlassen, was in der Praxis zu zuverlässigeren Ergebnissen ueber alle Browser hinweg fuehrt.


/* Chrome, Safari, Edge (Blink/WebKit) */
input[type="range"]::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 999px;
  background: #e5e7eb;
}

/* Firefox */
input[type="range"]::-moz-range-track {
  height: 6px;
  border-radius: 999px;
  background: #e5e7eb;
}

4. Gefuellten Bereich ohne JS-Bibliothek darstellen

Der gefuellte Bereich links vom Thumb, der visuell den aktuellen Fortschritt anzeigt, ist der Teil eines Range-Inputs, der am meisten Browser-Unterschiede aufweist. Firefox bietet mit ::-moz-range-progress ein dediziertes Pseudo-Element dafuer, waehrend Chrome und Safari keine aequivalente Loesung anbieten. Der etablierte Trick fuer WebKit-Browser ist ein linear-gradient-Hintergrund auf dem Track selbst, dessen Farbstopp sich exakt am aktuellen Prozentwert des Sliders befindet.

Damit dieser Farbstopp sich mit dem Wert des Sliders mitbewegt, ohne dass eine schwere JavaScript-Bibliothek geladen werden muss, genuegt eine einzige CSS-Custom-Property, die per oninput-Attribut mit wenigen Zeilen Vanilla-JavaScript aktualisiert wird. Dieser Ansatz bleibt vollstaendig CSS-getrieben, was Design, Farben und Uebergaenge angeht, und benoetigt lediglich eine minimale Berechnung des Prozentwerts in JavaScript, keine externe Slider-Bibliothek mit eigenem Rendering-Layer.


/* The fill percentage is stored in a CSS custom property, updated from JS */
input[type="range"] {
  --range-progress: 50%;
}

/* WebKit/Blink: gradient background simulates a filled track */
input[type="range"]::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 999px;
  background: linear-gradient(
    to right,
    #7c3aed 0%,
    #7c3aed var(--range-progress),
    #e5e7eb var(--range-progress),
    #e5e7eb 100%
  );
}

/* Firefox: native progress pseudo-element, no gradient trick needed */
input[type="range"]::-moz-range-progress {
  height: 6px;
  border-radius: 999px;
  background: #7c3aed;
}

// Minimal vanilla JS: only computes the percentage, no slider library involved
document.querySelectorAll('input[type="range"]').forEach((slider) => {
  const updateFill = () => {
    const min = Number(slider.min || 0);
    const max = Number(slider.max || 100);
    const percent = ((Number(slider.value) - min) / (max - min)) * 100;
    slider.style.setProperty('--range-progress', `${percent}%`);
  };
  slider.addEventListener('input', updateFill);
  updateFill(); // set initial fill on page load
});

5. Tick-Marks und Wertebeschriftung mit datalist

Fuer Range-Slider mit diskreten Schritten, etwa eine Bewertungsskala von eins bis fuenf oder Groessenstufen S, M, L, XL, ist das native datalist-Element in Kombination mit dem list-Attribut des Range-Inputs die richtige Wahl. Der Browser zeichnet automatisch kleine Tick-Marks an den in datalist definierten Positionen, ohne dass eigenes JavaScript oder zusaetzliche DOM-Elemente noetig sind.

Die visuelle Gestaltung dieser Tick-Marks ist browserabhaengig eingeschraenkt, aber Chrome unterstuetzt inzwischen das Styling ueber ::-webkit-slider-container in Kombination mit generierten Inhalten, und in den meisten Projekten reicht die Standarddarstellung der Tick-Marks vollkommen aus, kombiniert mit eigenen Text-Labels unterhalb des Sliders, die per Flexbox positioniert werden und unabhaengig vom nativen Tick-Rendering bleiben.


/* Labels positioned independently below the slider, aligned via flexbox */
.range-labels {
  display: flex;
  justify-content: space-between;
  font-size: 0.75rem;
  color: #6b7280;
  margin-top: 0.5rem;
}

<input type="range" min="1" max="5" step="1" list="rating-ticks">
<datalist id="rating-ticks">
  <option value="1"></option>
  <option value="2"></option>
  <option value="3"></option>
  <option value="4"></option>
  <option value="5"></option>
</datalist>
<div class="range-labels">
  <span>Schlecht</span>
  <span>Neutral</span>
  <span>Exzellent</span>
</div>

6. Thumb-Design: Groesse, Schatten, Hover-Zustaende

Der Thumb eines Range-Inputs profitiert am meisten von individueller Gestaltung, weil er das Element ist, das der Nutzer aktiv greift und bewegt. Eine ausreichend grosse Klickflaeche, mindestens 20 mal 20 Pixel fuer Desktop und 24 mal 24 Pixel fuer Touch-Geraete, verbessert die Bedienbarkeit deutlich gegenueber dem oft zu kleinen nativen Standard-Thumb. Ein subtiler Schatten und ein sichtbarer Hover-Zustand kommunizieren zusaetzlich, dass es sich um ein interaktives Element handelt.

Wichtig ist ein deutlich sichtbarer active-Zustand waehrend des Ziehens, etwa eine leichte Vergroesserung oder ein staerkerer Schatten, weil Nutzer sonst nicht zuverlaessig erkennen, ob der Thumb tatsaechlich gerade bewegt wird oder die Eingabe ins Leere laeuft. Dieser Zustand laesst sich ueber :active auf dem Thumb-Pseudo-Element selbst definieren und funktioniert unabhaengig vom oben beschriebenen Fuellstand-Trick.


input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #7c3aed;
  box-shadow: 0 2px 6px rgba(124, 58, 237, 0.4);
  margin-top: -8px;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

input[type="range"]::-webkit-slider-thumb:hover {
  box-shadow: 0 3px 8px rgba(124, 58, 237, 0.55);
}

input[type="range"]::-webkit-slider-thumb:active {
  transform: scale(1.15);
}

input[type="range"]::-moz-range-thumb {
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 50%;
  background: #7c3aed;
  box-shadow: 0 2px 6px rgba(124, 58, 237, 0.4);
}

7. Vertikale Range-Slider gestalten

Ein vertikaler Range-Input, etwa fuer eine Lautstaerkeregelung, laesst sich auf zwei Wegen umsetzen. Firefox unterstuetzt das native orient="vertical"-Attribut direkt auf dem Input, waehrend Chromium-Browser stattdessen entweder writing-mode: vertical-lr kombiniert mit direction: rtl benoetigen, oder die neuere Eigenschaft appearance: slider-vertical, die in aelteren Chrome-Versionen proprietaer war und mittlerweile breiter unterstuetzt wird.

In der Praxis ist die Kombination aus writing-mode und einer festen Breite plus Hoehe die zuverlässigste browserübergreifende Loesung, weil sie auf Standard-Eigenschaften basiert, statt auf einem browserspezifischen orient-Attribut. Der gefuellte-Bereich-Trick aus Abschnitt vier muss fuer die vertikale Variante angepasst werden, weil der Gradient dann von unten nach oben statt von links nach rechts verlaufen muss.


/* Cross-browser vertical range input via writing-mode */
.range-vertical {
  writing-mode: vertical-lr;
  direction: rtl;
  appearance: slider-vertical; /* Chromium fallback where supported */
  width: 6px;
  height: 160px;
}

8. Touch-Bedienbarkeit und Tastatur-Fokus

Ein oft unterschaetzter Aspekt beim Gestalten eines Range-Inputs ist die Mindestgroesse der Klickflaeche fuer Touch-Geraete. Die WCAG-Richtlinie 2.5.5 empfiehlt mindestens 24 mal 24 CSS-Pixel fuer interaktive Ziele, und ein zu klein gestalteter Thumb frustriert Nutzer auf Touchscreens erheblich, weil der Finger den schmalen nativen Thumb regelmaessig verfehlt. Eine grosszuegige, aber optisch dezente Klickflaeche, die groesser ist als das sichtbare Thumb-Icon, verbessert die Treffsicherheit ohne das Design zu beeintraechtigen.

Fuer Tastaturnutzer bleibt der native Range-Input vollstaendig bedienbar mit Pfeiltasten, Bild-auf, Bild-ab, Pos1 und Ende, solange kein appearance: none diese Funktionalitaet beeintraechtigt, was es nicht tut, weil appearance nur die Optik betrifft. Ein eigener Fokus-Ring mit :focus-visible ist dennoch Pflicht, weil appearance: none auch hier den System-Fokus-Ring entfernt und ohne Ersatz die Tastaturbedienbarkeit optisch unklar bleibt.

9. Nativer Range-Slider vs. JavaScript-Bibliothek

Ob ein nativer, mit CSS gestalteter Range-Input ausreicht oder eine externe JavaScript-Bibliothek noetig wird, haengt in erster Linie davon ab, ob eine einzelne Wertauswahl oder eine Bereichsauswahl mit zwei Griffen benoetigt wird. Die folgende Tabelle stellt beide Ansaetze anhand der wichtigsten Kriterien gegenueber.

Kriterium Nativer Range-Input mit CSS JS-Bibliothek (z.B. noUiSlider)
Bundle-Groesse 0 KB zusaetzlich Typisch 20 bis 40 KB
Tastatursteuerung Nativ, garantiert korrekt Muss von der Bibliothek implementiert sein
Doppel-Thumb (Bereichsauswahl) Nicht nativ moeglich Standardfeature
Mobile Wertanzeige waehrend Drag Nicht nativ, muss selbst gebaut werden Meist eingebaut
Wartungsaufwand Gering, reines CSS/HTML Abhaengigkeits-Updates noetig

Fuer einen einzelnen Wert ist der native Range-Input mit CSS-Gestaltung fast immer die bessere Wahl, weil er kein zusaetzliches Gewicht auf die Seite bringt und garantiert korrekte Tastatursteuerung mitliefert. Sobald eine Bereichsauswahl mit zwei Griffen noetig ist, etwa fuer einen Preisfilter von Minimum bis Maximum, stossen native Range-Inputs an ihre Grenze, weil ein einzelnes input type="range" nur einen Wert kennt und eine JS-Bibliothek oder zwei ueberlagerte Range-Inputs mit zusaetzlicher Logik erforderlich werden.

Mironsoft

Formular-UI, Slider und leichte Frontend-Loesungen

Range-Slider ohne unnoetige JavaScript-Last?

Wir bauen individuell gestaltete Range-Inputs mit reinem CSS, inklusive Fuellstand-Anzeige, Tick-Marks und Touch-optimiertem Thumb, ganz ohne schwere Slider-Bibliothek.

Slider-Design

Track, Thumb und Fuellstand markenkonform gestalten

Performance-Audit

Unnoetige JS-Bibliotheken durch native Loesungen ersetzen

Touch-Optimierung

Klickflaechen und Fokus-Zustaende nach WCAG anpassen

10. Zusammenfassung

Ein individuell gestalteter Range-Input erfordert getrennte CSS-Regeln fuer Track, Thumb und gefuellten Bereich, jeweils mit webkit- und moz-Praefixen. Der Fuellstand laesst sich ohne JS-Bibliothek darstellen, indem eine CSS-Custom-Property den aktuellen Prozentwert speichert und per minimaler Vanilla-JavaScript-Zeile bei jedem input-Event aktualisiert wird. Tick-Marks kommen nativ ueber datalist, vertikale Slider ueber writing-mode.

Fuer die Mehrheit der Anwendungsfaelle, ein einzelner Wert auf einer Skala, ist der native Range-Input mit CSS-Gestaltung der schwergewichtigen JS-Bibliothek klar vorzuziehen, weil er kein zusaetzliches Bundle-Gewicht mitbringt und garantiert korrekte Tastatursteuerung sowie Touch-Bedienbarkeit liefert. Nur bei einer echten Doppel-Thumb-Bereichsauswahl wird eine externe Loesung notwendig.

Range-Input gestalten — Das Wichtigste auf einen Blick

Drei Teile

Track, Thumb und Fuellstand jeweils getrennt mit webkit- und moz-Praefixen stylen.

Fuellstand ohne JS-Lib

CSS-Custom-Property plus minimale Vanilla-JS-Zeile ersetzen komplette Slider-Bibliotheken.

Tick-Marks

Natives datalist-Element mit list-Attribut, kein JavaScript noetig.

Touch und Tastatur

Mindestens 24 mal 24 Pixel Klickflaeche, eigener Fokus-Ring nach appearance: none.

11. FAQ: Range-Input gestalten

1Warum ist Range schwerer zu stylen als Checkbox?
Drei separate Teile mit eigenen Selektoren: Track, Thumb und gefuellter Bereich.
2Wie zeige ich den Fuellstand ohne JS-Lib?
CSS-Custom-Property plus linear-gradient, aktualisiert per minimaler Vanilla-JS-Zeile beim input-Event.
3Warum reicht accent-color nicht immer?
Erlaubt keine individuelle Track-Hoehe oder Thumb-Form, nur Farbe.
4Wie fuege ich Tick-Marks hinzu?
Mit datalist und dem list-Attribut, ohne JavaScript.
5Wie gestalte ich einen vertikalen Slider?
writing-mode: vertical-lr kombiniert mit direction: rtl.
6Welche Mindestgroesse fuer Touch?
Mindestens 24 mal 24 CSS-Pixel nach WCAG 2.5.5.
7Bleibt die Tastatursteuerung erhalten?
Ja, appearance: none aendert nur die Optik.
8Warum den Fokus-Ring ersetzen?
appearance: none entfernt den nativen Ring, ein eigener ist fuer Barrierefreiheit Pflicht.
9Wann brauche ich trotzdem eine JS-Bibliothek?
Bei Bereichsauswahl mit zwei Griffen, etwa einem Preisfilter.
10Unterschied Firefox vs. Chrome beim Fuellstand?
Firefox hat moz-range-progress, Chrome braucht linear-gradient-Trick.