Simple Dual Range Slider In HTML CSS

Once upon a time, a student had to implement a min/max dual range slider in her project. She cleverly searched, copy-and-pasted a solution on the Internet. But when tasked to customize it, she went into a “don’t know how” trance. Well, let Master Coffee walk you through the mechanics, so you can customize it as much as you like – Let’s go.

 

CODE DOWNLOAD

I have released this under the MIT license, feel free to use it in your own project – Personal or commercial. Some form of credits will be nice though. 🙂

 

 

VIDEO TUTORIAL

 

DUAL RANGE SLIDER DEMO

0
0

My Wordpess theme is messing up the styles a little bit… Download the zip above and see the “clean” version if you want.

 

THUMB & TRACK

Before we proceed, here’s a quick “terminology” for the beginners.

  • The red round button you drag around is called the “thumb”.
  • The grey horizontal line in the background is called the “track”.

 

 

PART 1) THE HTML

dual.html
<div class="drange">
  <input type="range" min="1" max="100" value="20">
  <input type="range" min="1" max="100" value="70">
  <div class="dmin">0</div>
  <div class="dmax">0</div>
</div>
  • Start by creating a <div class="drange"> container.
  • Insert 2 <input type="range"> sliders. One for the “min”, another for the “max”.
  • Lastly, this is kind of optional. But if you want to display the current value, also add <div class="dmin"> <div class="dmax">.

 

PART 2) THE CSS – STACK THE SLIDERS

dual.css
/* (PART A) STACK RANGE SLIDERS */
.drange {
  position: relative;
}
.drange input[type="range"] {
  position: absolute;
  width: 100%;
  pointer-events: none;
}
.drange input[type=range]::-webkit-slider-thumb {
  pointer-events: all;
}
.drange input[type=range]::-moz-range-thumb {
  pointer-events: all;
}

The first thing we do, stack the range sliders on top of each other.

  • Set the container to position: relative, and the sliders to position: absolute.
  • That’s about it, but only the top slider can be clicked with this “stacking”. To work around, we play with the pointer events.
    • Set both sliders to pointer-events: none.
    • But set the thumb to pointer-events: all.

 

 

PART 3) THE CSS – HIDE DEFAULT SLIDER STYLES

dual.css
/* (PART B) WRAPPER : CENTER SLIDERS & DIMENSIONS */
.drange {
  display: flex; align-items: center;
  max-width: 400px; height: 50px;
  margin: 10px 10px 20px 10px;
}
 
/* (PART C) HIDE DEFAULT SLIDER STYLES */
.drange input[type=range] {
  appearance: none;
  background: none;
}
.drange input[type=range]::-webkit-slider-thumb {
  appearance: none;
}
.drange input[type=range]:focus {
  outline: none;
}

This section is pretty self-explanatory. To customize the sliders, we have to hide the default styles for the thumb and track.

 

 

PART 4) THE CSS – CUSTOM RANGE SLIDER

dual.css
/* (PART D) CUSTOM THUMB */
.drange input[type=range]::-webkit-slider-thumb {
  width: 20px; height: 20px;
  border: 0; border-radius: 50%;
  background: #be1e1e;
  cursor: pointer;
}
.drange input[type=range]::-moz-range-thumb {
  width: 20px; height: 20px;
  border: 0; border-radius: 50%;
  background: #be1e1e;
  cursor: pointer;
}

/* (PART E) CUSTOM TRACK : FIRST SLIDER ONLY */
.drange input[type=range]:first-child::-webkit-slider-runnable-track {
  background: #3e3e3e
}
.drange input[type=range]:first-child::-moz-range-track {
  background: #3e3e3e;
}

/* (PART F) TO "RESIZE" TRACK */
/* (20px - 6px) / 2 = 7 px */
.drange input[type=range]::-webkit-slider-runnable-track {
  height: 6px;
}
.drange input[type=range]::-moz-range-track {
  height: 6px;
}
.drange input[type=range]::-webkit-slider-thumb {
  margin-top: -7px;
}

/* (PART G) MIN/MAX VALUE */
.drange .dmin, .drange .dmax {
  position: absolute; bottom: -5px;
  font-size: 14px; font-weight: 700;
}
.drange .dmin { left: 0; }
.drange .dmax { right: 0; }
  • Customizing the thumb is easy.
    • Use ::-webkit-slider-thumb for Webkit-based browsers (Chrome, Edge, Opera).
    • Use ::-moz-range-thumb for Firefox.
    • Just treat the thumb as a “normal <div>“. Set the dimensions, colors, etc…
  • Customizing the track is not so straightforward.
    • Use ::-webkit-slider-runnable-track for Webkit-based browsers.
    • Use ::-moz-range-track for Firefox.
    • The gist is to set the height and background color for the track, but there is a “funky bug” with Webkit.
    • Firefox will automatically center the track, Webkit doesn’t. That is why we have to manually offset it with a negative margin.
    • Lastly, only draw the track for the first slider (set the background color). If both are set, there will be an irritating horizontal bar across one of the thumbs.

 

 

PART 5) JAVASCRIPT – RESTRICT THE MIN/MAX

dual.js
window.addEventListener("load", () => {
  // (PART A) LOOP THROUGH DUAL RANGE SLIDERS
  document.querySelectorAll(".drange").forEach(drange => {
    // (PART B) GET RANGE PICKERS & VALUE DISPLAY
    let ranges = drange.querySelectorAll("input[type=range]"),
    dmin = drange.querySelector(".dmin"),
    dmax = drange.querySelector(".dmax");

    // (PART C) MIN CANNOT BE MORE THAN MAX
    ranges[0].addEventListener("input", e => {
      if (+ranges[0].value >= +ranges[1].value) {
        ranges[0].value = +ranges[1].value - 1;
      }
      dmin.innerHTML = ranges[0].value;
    });

    // (PART D) MAX CANNOT BE LESS THAN MIN
    ranges[1].addEventListener("input", e => {
      if (+ranges[1].value <= +ranges[0].value) {
        ranges[1].value = +ranges[0].value + 1;
      }
      dmax.innerHTML = ranges[1].value;
    });

    // (PART E) INIT VALUE DISPLAY
    dmin.innerHTML = ranges[0].value;
    dmax.innerHTML = ranges[1].value;
  });
});

Lastly, we need a small Javascript snippet to control the slider. TLDR:

  • The min value cannot be equal or greater than the max.
  • The max value cannot be equal or lesser than the min.
  • Update the value display when the thumb is being shifted around.

 

 

THE END – SMALL NOTES

That’s all for this tutorial and sharing. Before we end, here are a few common questions I foresee people asking:

  • Users who are not on Chrome, Opera, Edge, Brave, Firefox may see a “broken slider”. Nothing you can do… Unless you rebuild an entire custom slider that does not use ::-webkit and ::-moz.
  • How to get the values – Just some CSS selector magic.
    • <div class="drange" id="demo">
    • var val = document.querySelectorAll("#demo input[type=range]");
    • That’s all. val[0] is the min, and val[1] is the max.