/* Dark range sliders for dark interfaces. A real <input type="range"> styled through the WebKit and Firefox
pseudo-elements; --p (0 to 1) is set by the script below. Every track is at least 3:1 against #121a2e. */
.dk{--dk-accent:#22d3ee;--dk-track:#5f6f8a;--dk-bg:#121a2e;--dk-thumb:20px;--dk-h:6px;--p:0;display:grid;gap:14px}
.dk-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px}
.dk-head label{font-size:.95rem;font-weight:600;color:#e2e8f0}
.dk-head output{font-size:.95rem;font-weight:700;color:var(--dk-accent);font-variant-numeric:tabular-nums}
.dk input[type="range"]{-webkit-appearance:none;appearance:none;display:block;width:100%;height:var(--dk-thumb);margin:0;background:none;cursor:pointer}
.dk input[type="range"]:focus-visible{outline:none}
.dk input[type="range"]::-webkit-slider-runnable-track{height:var(--dk-h);border-radius:999px;
background:linear-gradient(to right,var(--dk-accent) 0 calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p)),var(--dk-track) 0)}
.dk input[type="range"]::-moz-range-track{height:var(--dk-h);border-radius:999px;
background:linear-gradient(to right,var(--dk-accent) 0 calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p)),var(--dk-track) 0)}
.dk input[type="range"]::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;box-sizing:border-box;
width:var(--dk-thumb);height:var(--dk-thumb);margin-top:calc((var(--dk-h) - var(--dk-thumb)) / 2);
border:0;border-radius:50%;background:#fff;box-shadow:0 0 0 4px rgba(34,211,238,.25),0 0 14px rgba(34,211,238,.7)}
.dk input[type="range"]::-moz-range-thumb{box-sizing:border-box;width:var(--dk-thumb);height:var(--dk-thumb);
border:0;border-radius:50%;background:#fff;box-shadow:0 0 0 4px rgba(34,211,238,.25),0 0 14px rgba(34,211,238,.7)}
.dk input[type="range"]:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 3px var(--dk-bg),0 0 0 5px #fff}
.dk input[type="range"]:focus-visible::-moz-range-thumb{box-shadow:0 0 0 3px var(--dk-bg),0 0 0 5px #fff}
/* neon: the filled part glows */
.dk.neon input[type="range"]::-webkit-slider-runnable-track{box-shadow:0 0 12px rgba(34,211,238,.35)}
.dk.neon input[type="range"]::-moz-range-track{box-shadow:0 0 12px rgba(34,211,238,.35)}
/* centre zero: fill runs from the middle to the thumb, a tick marks 0 */
.dk.zero{--dk-accent:#fbbf24}
.dk.zero input[type="range"]::-webkit-slider-runnable-track{background:
linear-gradient(#e2e8f0,#e2e8f0) center / 2px 100% no-repeat,
linear-gradient(to right,var(--dk-track) 0 min(50%,calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p))),
var(--dk-accent) 0 max(50%,calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p))),var(--dk-track) 0)}
.dk.zero input[type="range"]::-moz-range-track{background:
linear-gradient(#e2e8f0,#e2e8f0) center / 2px 100% no-repeat,
linear-gradient(to right,var(--dk-track) 0 min(50%,calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p))),
var(--dk-accent) 0 max(50%,calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p))),var(--dk-track) 0)}
.dk.zero input[type="range"]::-webkit-slider-thumb{background:var(--dk-accent);box-shadow:0 0 0 4px rgba(251,191,36,.2)}
.dk.zero input[type="range"]::-moz-range-thumb{background:var(--dk-accent);box-shadow:0 0 0 4px rgba(251,191,36,.2)}
.dk-scale{display:flex;justify-content:space-between;font-size:.78rem;color:#94a3b8;font-variant-numeric:tabular-nums}
/* LED level: ten blocks light up to the thumb; the gaps are painted in the card colour */
.dk.led{--dk-accent:#a3e635;--dk-thumb:6px;--dk-h:14px}
.dk.led input[type="range"]{height:28px}
.dk.led input[type="range"]::-webkit-slider-runnable-track{border-radius:3px;background:
repeating-linear-gradient(to right,transparent 0 calc(10% - 4px),var(--dk-bg) 0 10%),
linear-gradient(to right,var(--dk-accent) 0 calc((var(--p) * 9 + 1) * 10%),var(--dk-track) 0)}
.dk.led input[type="range"]::-moz-range-track{border-radius:3px;background:
repeating-linear-gradient(to right,transparent 0 calc(10% - 4px),var(--dk-bg) 0 10%),
linear-gradient(to right,var(--dk-accent) 0 calc((var(--p) * 9 + 1) * 10%),var(--dk-track) 0)}
.dk.led input[type="range"]::-webkit-slider-thumb{width:6px;height:28px;margin-top:-7px;border-radius:3px;box-shadow:0 0 0 2px var(--dk-bg)}
.dk.led input[type="range"]::-moz-range-thumb{width:6px;height:28px;border-radius:3px;box-shadow:0 0 0 2px var(--dk-bg)}
.dk.led input[type="range"]:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--dk-bg),0 0 0 4px #fff}
.dk.led input[type="range"]:focus-visible::-moz-range-thumb{box-shadow:0 0 0 2px var(--dk-bg),0 0 0 4px #fff}
/* hue: the track is the colour wheel unrolled and the thumb takes the chosen hue */
.dk.hue{--dk-thumb:26px;--dk-h:12px}
.dk.hue .dk-head output{color:#e2e8f0;display:inline-flex;align-items:center;gap:8px}
.dk-swatch{width:14px;height:14px;border-radius:4px;background:hsl(calc(var(--p) * 360) 85% 60%);box-shadow:0 0 0 1px rgba(255,255,255,.4)}
.dk.hue input[type="range"]::-webkit-slider-runnable-track{background:linear-gradient(to right,
hsl(0 85% 60%),hsl(60 85% 60%),hsl(120 85% 60%),hsl(180 85% 60%),hsl(240 85% 60%),hsl(300 85% 60%),hsl(360 85% 60%))}
.dk.hue input[type="range"]::-moz-range-track{background:linear-gradient(to right,
hsl(0 85% 60%),hsl(60 85% 60%),hsl(120 85% 60%),hsl(180 85% 60%),hsl(240 85% 60%),hsl(300 85% 60%),hsl(360 85% 60%))}
.dk.hue input[type="range"]::-webkit-slider-thumb{border:4px solid #fff;background:hsl(calc(var(--p) * 360) 85% 60%);box-shadow:0 2px 8px rgba(0,0,0,.5)}
.dk.hue input[type="range"]::-moz-range-thumb{border:4px solid #fff;background:hsl(calc(var(--p) * 360) 85% 60%);box-shadow:0 2px 8px rgba(0,0,0,.5)}
JavaScript
// Keeps each slider's fill (--p) and its readout in step with the value.
document.querySelectorAll('.dk input[type="range"]').forEach(function (range) {
var field = range.closest('.dk');
var out = field.querySelector('.dk-text') || field.querySelector('output');
function sync() {
var v = Number(range.value), d = Number(range.dataset.decimals || 0);
var sign = v < 0 ? '−' : (v > 0 && range.hasAttribute('data-signed') ? '+' : '');
var text = sign + Math.abs(v).toFixed(d) + (range.dataset.suffix || '');
field.style.setProperty('--p', (v - range.min) / (range.max - range.min));
out.textContent = text;
range.setAttribute('aria-valuetext', text);
}
range.addEventListener('input', sync);
sync();
});
/* Dark range sliders: Bootstrap .form-range under data-bs-theme="dark", restyled through the WebKit and Firefox
pseudo-elements; --p (0 to 1) is set by the script below. Every track is at least 3:1 against #121a2e. */
.dk{--dk-accent:#22d3ee;--dk-track:#5f6f8a;--dk-bg:#121a2e;--dk-thumb:20px;--dk-h:6px;--p:0;display:grid;gap:14px}
.dk .form-label{font-size:.95rem;color:#e2e8f0}
.dk .dk-value{font-size:.95rem;color:var(--dk-accent);font-variant-numeric:tabular-nums}
.dk .form-range{height:var(--dk-thumb)}
.dk .form-range::-webkit-slider-runnable-track{height:var(--dk-h);border-radius:999px;
background:linear-gradient(to right,var(--dk-accent) 0 calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p)),var(--dk-track) 0)}
.dk .form-range::-moz-range-track{height:var(--dk-h);border-radius:999px;
background:linear-gradient(to right,var(--dk-accent) 0 calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p)),var(--dk-track) 0)}
.dk .form-range::-webkit-slider-thumb{box-sizing:border-box;
width:var(--dk-thumb);height:var(--dk-thumb);margin-top:calc((var(--dk-h) - var(--dk-thumb)) / 2);
border:0;border-radius:50%;background:#fff;box-shadow:0 0 0 4px rgba(34,211,238,.25),0 0 14px rgba(34,211,238,.7)}
.dk .form-range::-moz-range-thumb{box-sizing:border-box;width:var(--dk-thumb);height:var(--dk-thumb);
border:0;border-radius:50%;background:#fff;box-shadow:0 0 0 4px rgba(34,211,238,.25),0 0 14px rgba(34,211,238,.7)}
.dk .form-range:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 3px var(--dk-bg),0 0 0 5px #fff}
.dk .form-range:focus-visible::-moz-range-thumb{box-shadow:0 0 0 3px var(--dk-bg),0 0 0 5px #fff}
/* neon: the filled part glows */
.dk.neon .form-range::-webkit-slider-runnable-track{box-shadow:0 0 12px rgba(34,211,238,.35)}
.dk.neon .form-range::-moz-range-track{box-shadow:0 0 12px rgba(34,211,238,.35)}
/* centre zero: fill runs from the middle to the thumb, a tick marks 0 */
.dk.zero{--dk-accent:#fbbf24}
.dk.zero .form-range::-webkit-slider-runnable-track{background:
linear-gradient(#e2e8f0,#e2e8f0) center / 2px 100% no-repeat,
linear-gradient(to right,var(--dk-track) 0 min(50%,calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p))),
var(--dk-accent) 0 max(50%,calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p))),var(--dk-track) 0)}
.dk.zero .form-range::-moz-range-track{background:
linear-gradient(#e2e8f0,#e2e8f0) center / 2px 100% no-repeat,
linear-gradient(to right,var(--dk-track) 0 min(50%,calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p))),
var(--dk-accent) 0 max(50%,calc(var(--dk-thumb) / 2 + (100% - var(--dk-thumb)) * var(--p))),var(--dk-track) 0)}
.dk.zero .form-range::-webkit-slider-thumb{background:var(--dk-accent);box-shadow:0 0 0 4px rgba(251,191,36,.2)}
.dk.zero .form-range::-moz-range-thumb{background:var(--dk-accent);box-shadow:0 0 0 4px rgba(251,191,36,.2)}
.dk-scale{font-size:.78rem;color:#94a3b8;font-variant-numeric:tabular-nums}
/* LED level: ten blocks light up to the thumb; the gaps are painted in the card colour */
.dk.led{--dk-accent:#a3e635;--dk-thumb:6px;--dk-h:14px}
.dk.led .form-range{height:28px}
.dk.led .form-range::-webkit-slider-runnable-track{border-radius:3px;background:
repeating-linear-gradient(to right,transparent 0 calc(10% - 4px),var(--dk-bg) 0 10%),
linear-gradient(to right,var(--dk-accent) 0 calc((var(--p) * 9 + 1) * 10%),var(--dk-track) 0)}
.dk.led .form-range::-moz-range-track{border-radius:3px;background:
repeating-linear-gradient(to right,transparent 0 calc(10% - 4px),var(--dk-bg) 0 10%),
linear-gradient(to right,var(--dk-accent) 0 calc((var(--p) * 9 + 1) * 10%),var(--dk-track) 0)}
.dk.led .form-range::-webkit-slider-thumb{width:6px;height:28px;margin-top:-7px;border-radius:3px;box-shadow:0 0 0 2px var(--dk-bg)}
.dk.led .form-range::-moz-range-thumb{width:6px;height:28px;border-radius:3px;box-shadow:0 0 0 2px var(--dk-bg)}
.dk.led .form-range:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--dk-bg),0 0 0 4px #fff}
.dk.led .form-range:focus-visible::-moz-range-thumb{box-shadow:0 0 0 2px var(--dk-bg),0 0 0 4px #fff}
/* hue: the track is the colour wheel unrolled and the thumb takes the chosen hue */
.dk.hue{--dk-thumb:26px;--dk-h:12px}
.dk.hue .dk-value{color:#e2e8f0}
.dk-swatch{width:14px;height:14px;border-radius:4px;background:hsl(calc(var(--p) * 360) 85% 60%);box-shadow:0 0 0 1px rgba(255,255,255,.4)}
.dk.hue .form-range::-webkit-slider-runnable-track{background:linear-gradient(to right,
hsl(0 85% 60%),hsl(60 85% 60%),hsl(120 85% 60%),hsl(180 85% 60%),hsl(240 85% 60%),hsl(300 85% 60%),hsl(360 85% 60%))}
.dk.hue .form-range::-moz-range-track{background:linear-gradient(to right,
hsl(0 85% 60%),hsl(60 85% 60%),hsl(120 85% 60%),hsl(180 85% 60%),hsl(240 85% 60%),hsl(300 85% 60%),hsl(360 85% 60%))}
.dk.hue .form-range::-webkit-slider-thumb{border:4px solid #fff;background:hsl(calc(var(--p) * 360) 85% 60%);box-shadow:0 2px 8px rgba(0,0,0,.5)}
.dk.hue .form-range::-moz-range-thumb{border:4px solid #fff;background:hsl(calc(var(--p) * 360) 85% 60%);box-shadow:0 2px 8px rgba(0,0,0,.5)}
JavaScript
// Keeps each slider's fill (--p) and its readout in step with the value.
document.querySelectorAll('.dk .form-range').forEach(function (range) {
var field = range.closest('.dk');
var out = field.querySelector('.dk-text') || field.querySelector('output');
function sync() {
var v = Number(range.value), d = Number(range.dataset.decimals || 0);
var sign = v < 0 ? '−' : (v > 0 && range.hasAttribute('data-signed') ? '+' : '');
var text = sign + Math.abs(v).toFixed(d) + (range.dataset.suffix || '');
field.style.setProperty('--p', (v - range.min) / (range.max - range.min));
out.textContent = text;
range.setAttribute('aria-valuetext', text);
}
range.addEventListener('input', sync);
sync();
});
// Keeps each slider's fill (--p) and its readout in step with the value.
document.querySelectorAll('.dk input[type="range"]').forEach(function (range) {
var field = range.closest('.dk');
var out = field.querySelector('.dk-text') || field.querySelector('output');
function sync() {
var v = Number(range.value), d = Number(range.dataset.decimals || 0);
var sign = v < 0 ? '−' : (v > 0 && range.hasAttribute('data-signed') ? '+' : '');
var text = sign + Math.abs(v).toFixed(d) + (range.dataset.suffix || '');
field.style.setProperty('--p', (v - range.min) / (range.max - range.min));
out.textContent = text;
range.setAttribute('aria-valuetext', text);
}
range.addEventListener('input', sync);
sync();
});
About this set
Four sliders drawn for dark interfaces, where a light theme slider loses its track against the background. Neon glow gives a bass boost control a cyan fill with a soft glow and a white thumb with a halo. Centre zero is a photo editor exposure control from minus 2 to plus 2 EV in tenths, with an amber fill that grows from a tick at zero towards the thumb. LED level splits a fan speed track into ten blocks that light up in lime to the chosen level, and the thumb is a slim white bar that sits inside the last lit block. Hue picker unrolls the colour wheel into the track and fills the thumb and a small swatch with the chosen hue. All are real range inputs on a #121a2e card, and every unfilled track keeps at least 3:1 contrast against it. The LED gaps are painted in the card colour over a quantised fill, and the hue comes from calc(var(–p) * 360) inside hsl(), so a short script only has to set –p and write the value into the output and aria-valuetext.
What’s included
Neon, centre-zero, LED and hue variants
Unfilled tracks at 3:1 or more on the dark card
Centre-zero fill for signed values such as exposure
Quantised LED blocks that always line up with the thumb
Bootstrap version runs under data-bs-theme="dark"
Accessibility
Every slider has a visible label and a readout, and aria-valuetext carries the formatted value, such as +0.7 EV, 6 of 10 or 262°. Keyboard focus draws a white ring separated from the thumb by a gap in the card colour, so it stays visible on the cyan and amber thumbs. Nothing animates.
Customise it
Change --dk-accent, --dk-track, --dk-bg, --dk-thumb and --dk-h on .dk (plain CSS and Bootstrap); --dk-bg must match the card so the LED gaps and focus gap blend in. In Tailwind edit the --color-dk-* theme colours.