17 CSS Range Sliders07 / 17

CSS + JSMIT licensed

Vertical Audio Equalizer Slider

A 10-band mixing console equalizer with copper-toned vertical pill sliders sitting in inset steel grooves, per-channel dB readouts, and one-click preset buttons for Flat, Bass Boost, Treble, and Vocal modes.

Published

Live Demo
Try it

The code

<div class="rs-07">
  <div class="rs-07__console">
    <div class="rs-07__header">
      <div class="rs-07__title">Equalizer</div>
      <div class="rs-07__leds">
        <div class="rs-07__led"></div>
        <div class="rs-07__led"></div>
        <div class="rs-07__led"></div>
      </div>
    </div>
    <div class="rs-07__eq-row" id="rs-07-row"></div>
    <div class="rs-07__presets">
      <button class="rs-07__preset active" data-preset="flat">Flat</button>
      <button class="rs-07__preset" data-preset="bass">Bass Boost</button>
      <button class="rs-07__preset" data-preset="treble">Treble</button>
      <button class="rs-07__preset" data-preset="vocal">Vocal</button>
    </div>
  </div>
</div>
.rs-07,
.rs-07 *,
.rs-07 *::before,
.rs-07 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.rs-07 ::selection {
  background: #b87333;
  color: #fff;
}

.rs-07 {
  --bg: #111318;
  --panel: #1a1d24;
  --border: #2d3240;
  --copper: #b87333;
  --copper-lit: #d4925a;
  --steel: #4a5568;
  --text: #e2e8f0;
  --muted: #64748b;
  background: var(--bg);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px 24px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

.rs-07__console {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 28px 32px;
  max-width: 480px;
  width: 100%;
  box-shadow: 0 20px 60px rgba(0,0,0,0.6);
}

.rs-07__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 28px;
}

.rs-07__title {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: 2px;
  text-transform: uppercase;
}

.rs-07__leds {
  display: flex;
  gap: 5px;
}

.rs-07__led {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.rs-07__led:nth-child(1) {
  background: #ff5f57;
  box-shadow: 0 0 6px #ff5f57;
}

.rs-07__led:nth-child(2) {
  background: #febc2e;
  box-shadow: 0 0 6px #febc2e;
}

.rs-07__led:nth-child(3) {
  background: #28c840;
  box-shadow: 0 0 6px #28c840;
}

.rs-07__eq-row {
  display: flex;
  gap: 0;
  justify-content: space-around;
  align-items: flex-end;
  height: 200px;
  margin-bottom: 16px;
}

.rs-07__channel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  height: 100%;
}

.rs-07__slider-wrap {
  position: relative;
  height: 160px;
  width: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.rs-07__groove {
  position: absolute;
  width: 6px;
  height: 100%;
  background: linear-gradient(180deg, #2d3240 0%, #1a1d24 100%);
  border-radius: 3px;
  box-shadow: inset 2px 2px 4px rgba(0,0,0,0.6), inset -1px -1px 3px rgba(255,255,255,0.04);
}

.rs-07__vert-input {
  -webkit-appearance: slider-vertical;
  writing-mode: vertical-lr;
  direction: rtl;
  appearance: none;
  width: 32px;
  height: 160px;
  background: transparent;
  outline: none;
  cursor: pointer;
  position: relative;
  z-index: 2;
}

.rs-07__vert-input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 30px;
  height: 18px;
  background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
  border-radius: 4px;
  border: 1px solid rgba(255,255,255,0.15);
  box-shadow: 0 2px 8px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.2);
  position: relative;
  cursor: grab;
  transition: box-shadow 0.15s;
}

.rs-07__vert-input::-webkit-slider-thumb::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 20%;
  right: 20%;
  height: 2px;
  background: rgba(0,0,0,0.4);
  transform: translateY(-50%);
}

.rs-07__vert-input:active::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px rgba(184,115,51,0.3), 0 2px 8px rgba(0,0,0,0.5);
  cursor: grabbing;
}

.rs-07__vert-input::-moz-range-thumb {
  width: 30px;
  height: 18px;
  border-radius: 4px;
  background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
  border: 1px solid rgba(255,255,255,0.15);
  cursor: grab;
}

.rs-07__chan-label {
  font-size: 10px;
  font-weight: 600;
  color: var(--copper);
  letter-spacing: 1px;
  text-transform: uppercase;
}

.rs-07__chan-val {
  font-size: 10px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 28px;
  text-align: center;
}

.rs-07__presets {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.rs-07__preset {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 11px;
  padding: 5px 12px;
  border-radius: 20px;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s, background 0.2s;
}

.rs-07__preset:hover,
.rs-07__preset.active {
  border-color: var(--copper);
  color: var(--copper);
  background: rgba(184,115,51,0.1);
}

@media (prefers-reduced-motion: reduce) {
  .rs-07__preset {
    transition: none;
  }
}
(function(){
  const channels = [
    {label:'32', val:50}, {label:'64', val:60}, {label:'125', val:70},
    {label:'250', val:65}, {label:'500', val:50}, {label:'1K', val:55},
    {label:'2K', val:60}, {label:'4K', val:58}, {label:'8K', val:50}, {label:'16K', val:45}
  ];
  const presets = {
    flat: [50,50,50,50,50,50,50,50,50,50],
    bass: [80,78,72,65,55,48,44,42,40,38],
    treble: [40,40,42,44,50,58,68,75,78,80],
    vocal: [38,42,50,65,72,70,65,55,48,42],
  };
  const row = document.getElementById('rs-07-row');
  const sliders = [];
  channels.forEach((ch, i) => {
    const col = document.createElement('div');
    col.className = 'rs-07__channel';
    const valEl = document.createElement('div');
    valEl.className = 'rs-07__chan-val';
    valEl.textContent = (ch.val - 50 >= 0 ? '+' : '') + (ch.val - 50);
    const wrap = document.createElement('div');
    wrap.className = 'rs-07__slider-wrap';
    const groove = document.createElement('div');
    groove.className = 'rs-07__groove';
    const inp = document.createElement('input');
    inp.type = 'range'; inp.min = 0; inp.max = 100; inp.value = ch.val;
    inp.className = 'rs-07__vert-input';
    inp.setAttribute('orient','vertical');
    inp.addEventListener('input', () => {
      valEl.textContent = (+inp.value - 50 >= 0 ? '+' : '') + (+inp.value - 50);
    });
    wrap.appendChild(groove); wrap.appendChild(inp);
    const label = document.createElement('div');
    label.className = 'rs-07__chan-label';
    label.textContent = ch.label;
    col.appendChild(valEl); col.appendChild(wrap); col.appendChild(label);
    row.appendChild(col);
    sliders.push(inp);
  });
  document.querySelectorAll('.rs-07__preset').forEach(btn => {
    btn.addEventListener('click', () => {
      document.querySelectorAll('.rs-07__preset').forEach(b => b.classList.remove('active'));
      btn.classList.add('active');
      const vals = presets[btn.dataset.preset];
      sliders.forEach((s, i) => {
        s.value = vals[i];
        s.dispatchEvent(new Event('input'));
      });
    });
  });
})();
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Range Slider from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Vertical Audio Equalizer Slider
Source: https://codefronts.com/components/css-range-sliders/vertical-audio-equalizer-slider/

A 10-band mixing console equalizer with copper-toned vertical pill sliders sitting in inset steel grooves, per-channel dB readouts, and one-click preset buttons for Flat, Bass Boost, Treble, and Vocal modes.
## HTML
```html
<div class="rs-07">
  <div class="rs-07__console">
    <div class="rs-07__header">
      <div class="rs-07__title">Equalizer</div>
      <div class="rs-07__leds">
        <div class="rs-07__led"></div>
        <div class="rs-07__led"></div>
        <div class="rs-07__led"></div>
      </div>
    </div>
    <div class="rs-07__eq-row" id="rs-07-row"></div>
    <div class="rs-07__presets">
      <button class="rs-07__preset active" data-preset="flat">Flat</button>
      <button class="rs-07__preset" data-preset="bass">Bass Boost</button>
      <button class="rs-07__preset" data-preset="treble">Treble</button>
      <button class="rs-07__preset" data-preset="vocal">Vocal</button>
    </div>
  </div>
</div>
```
## CSS
```css
.rs-07,
.rs-07 *,
.rs-07 *::before,
.rs-07 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.rs-07 ::selection {
  background: #b87333;
  color: #fff;
}

.rs-07 {
  --bg: #111318;
  --panel: #1a1d24;
  --border: #2d3240;
  --copper: #b87333;
  --copper-lit: #d4925a;
  --steel: #4a5568;
  --text: #e2e8f0;
  --muted: #64748b;
  background: var(--bg);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px 24px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

.rs-07__console {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 28px 32px;
  max-width: 480px;
  width: 100%;
  box-shadow: 0 20px 60px rgba(0,0,0,0.6);
}

.rs-07__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 28px;
}

.rs-07__title {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: 2px;
  text-transform: uppercase;
}

.rs-07__leds {
  display: flex;
  gap: 5px;
}

.rs-07__led {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.rs-07__led:nth-child(1) {
  background: #ff5f57;
  box-shadow: 0 0 6px #ff5f57;
}

.rs-07__led:nth-child(2) {
  background: #febc2e;
  box-shadow: 0 0 6px #febc2e;
}

.rs-07__led:nth-child(3) {
  background: #28c840;
  box-shadow: 0 0 6px #28c840;
}

.rs-07__eq-row {
  display: flex;
  gap: 0;
  justify-content: space-around;
  align-items: flex-end;
  height: 200px;
  margin-bottom: 16px;
}

.rs-07__channel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  height: 100%;
}

.rs-07__slider-wrap {
  position: relative;
  height: 160px;
  width: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.rs-07__groove {
  position: absolute;
  width: 6px;
  height: 100%;
  background: linear-gradient(180deg, #2d3240 0%, #1a1d24 100%);
  border-radius: 3px;
  box-shadow: inset 2px 2px 4px rgba(0,0,0,0.6), inset -1px -1px 3px rgba(255,255,255,0.04);
}

.rs-07__vert-input {
  -webkit-appearance: slider-vertical;
  writing-mode: vertical-lr;
  direction: rtl;
  appearance: none;
  width: 32px;
  height: 160px;
  background: transparent;
  outline: none;
  cursor: pointer;
  position: relative;
  z-index: 2;
}

.rs-07__vert-input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 30px;
  height: 18px;
  background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
  border-radius: 4px;
  border: 1px solid rgba(255,255,255,0.15);
  box-shadow: 0 2px 8px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.2);
  position: relative;
  cursor: grab;
  transition: box-shadow 0.15s;
}

.rs-07__vert-input::-webkit-slider-thumb::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 20%;
  right: 20%;
  height: 2px;
  background: rgba(0,0,0,0.4);
  transform: translateY(-50%);
}

.rs-07__vert-input:active::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px rgba(184,115,51,0.3), 0 2px 8px rgba(0,0,0,0.5);
  cursor: grabbing;
}

.rs-07__vert-input::-moz-range-thumb {
  width: 30px;
  height: 18px;
  border-radius: 4px;
  background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
  border: 1px solid rgba(255,255,255,0.15);
  cursor: grab;
}

.rs-07__chan-label {
  font-size: 10px;
  font-weight: 600;
  color: var(--copper);
  letter-spacing: 1px;
  text-transform: uppercase;
}

.rs-07__chan-val {
  font-size: 10px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 28px;
  text-align: center;
}

.rs-07__presets {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.rs-07__preset {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 11px;
  padding: 5px 12px;
  border-radius: 20px;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s, background 0.2s;
}

.rs-07__preset:hover,
.rs-07__preset.active {
  border-color: var(--copper);
  color: var(--copper);
  background: rgba(184,115,51,0.1);
}

@media (prefers-reduced-motion: reduce) {
  .rs-07__preset {
    transition: none;
  }
}
```

## JavaScript
```js
(function(){
  const channels = [
    {label:'32', val:50}, {label:'64', val:60}, {label:'125', val:70},
    {label:'250', val:65}, {label:'500', val:50}, {label:'1K', val:55},
    {label:'2K', val:60}, {label:'4K', val:58}, {label:'8K', val:50}, {label:'16K', val:45}
  ];
  const presets = {
    flat: [50,50,50,50,50,50,50,50,50,50],
    bass: [80,78,72,65,55,48,44,42,40,38],
    treble: [40,40,42,44,50,58,68,75,78,80],
    vocal: [38,42,50,65,72,70,65,55,48,42],
  };
  const row = document.getElementById('rs-07-row');
  const sliders = [];
  channels.forEach((ch, i) => {
    const col = document.createElement('div');
    col.className = 'rs-07__channel';
    const valEl = document.createElement('div');
    valEl.className = 'rs-07__chan-val';
    valEl.textContent = (ch.val - 50 >= 0 ? '+' : '') + (ch.val - 50);
    const wrap = document.createElement('div');
    wrap.className = 'rs-07__slider-wrap';
    const groove = document.createElement('div');
    groove.className = 'rs-07__groove';
    const inp = document.createElement('input');
    inp.type = 'range'; inp.min = 0; inp.max = 100; inp.value = ch.val;
    inp.className = 'rs-07__vert-input';
    inp.setAttribute('orient','vertical');
    inp.addEventListener('input', () => {
      valEl.textContent = (+inp.value - 50 >= 0 ? '+' : '') + (+inp.value - 50);
    });
    wrap.appendChild(groove); wrap.appendChild(inp);
    const label = document.createElement('div');
    label.className = 'rs-07__chan-label';
    label.textContent = ch.label;
    col.appendChild(valEl); col.appendChild(wrap); col.appendChild(label);
    row.appendChild(col);
    sliders.push(inp);
  });
  document.querySelectorAll('.rs-07__preset').forEach(btn => {
    btn.addEventListener('click', () => {
      document.querySelectorAll('.rs-07__preset').forEach(b => b.classList.remove('active'));
      btn.classList.add('active');
      const vals = presets[btn.dataset.preset];
      sliders.forEach((s, i) => {
        s.value = vals[i];
        s.dispatchEvent(new Event('input'));
      });
    });
  });
})();
```

How this works

Vertical slider orientation uses the writing-mode: vertical-lr combined with direction: rtl CSS technique, which rotates the slider so dragging upward increases value — matching real-world fader behavior. The native <input> is given -webkit-appearance: slider-vertical for WebKit and a standard orient="vertical" attribute for Firefox. Each slider sits inside a .rs-07__slider-wrap that contains a decorative groove div using an inset box-shadow to simulate the metal channel.

Preset configurations are stored as flat value arrays in the presets object. When a preset button is clicked, the script iterates over all slider inputs, sets their .value, and dispatches a synthetic new Event('input') on each to trigger the shared update handler — keeping all readout labels in sync. The copper thumb gradient uses linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%) to fake a metallic highlight.

Make it yours

  • Add more frequency bands by pushing additional {label, val} entries to the channels[] array — the flex layout automatically redistributes width.
  • Change the copper color scheme to silver by updating the thumb gradient to linear-gradient(180deg, #e8e8e8 0%, #999 50%, #e8e8e8 100%) and adjusting the --copper variable.
  • Add a master gain fader by placing a separate horizontal input below the band array and multiplying all channel output values by a gain factor (0.0–2.0) in the update function.
  • Make the EQ interactive with a real Web Audio API by connecting BiquadFilterNode instances in a chain and setting their gain.value from each slider's (value - 50) / 50 * 12 dB mapping.
  • Show frequency response curve above the sliders by rendering an SVG polyline whose points are calculated from the channel values, updated live on every slider input event.

Gotchas — read before shipping

  • writing-mode: vertical-lr with direction: rtl can have inconsistent behavior in older Chromium versions — always test that upward drag increases value, and if not, swap to transform: rotate(-90deg) with adjusted track dimensions.
  • The orient="vertical" attribute is non-standard HTML but required for Firefox vertical sliders — it has no negative effect on other browsers so always include it.
  • Vertical sliders in Safari may render wider than specified — set an explicit height on the input and use max-width constraints to prevent layout overflow in the channel columns.

Browser support

ChromeSafariFirefoxEdge
80+14+78+80+

Firefox requires the non-standard orient="vertical" attribute; Safari may need -webkit-appearance:slider-vertical for correct vertical rendering.

Techniques used in this demo

Search CodeFronts

Loading…