How to style an HTML5 range input as a custom slider

November 5, 2018

You're working on a project, have a tight timeline and need to get your custom slider working now. You don't have time to mess around with javascript libraries, and you thought that HTML inputs can be hard to style depending on the type. Think again!

Html inputs can be easy to spice up, you just need to know some basics.

For a project, I had to make something that looks like this:



It not only has a custom track, but it has a different color progress bar and a custom draggable piece to adjust the slider's value. This is probably an easy job for a custom slider library, but I didn't really have time for finding a good one a quickly whipped up a solution myself, after quite a bit of trial and error. Looking back, a custom library might have been helpful, but sometimes it's nice to build something from scratch.

The difficulty comes because you have to style for individual browsers, and you also have to target each element individually. Kind of a pain...but a good learning experience!

HTML:
<input id="savingsSlider" class="savings-slider" name="savingsSlider" type="range"  step="0.01" min="0" max="1" value="0.6"/>

<div class="progress-bar-container">
     <div class="progress-bar">
</div>

There are four main elements to the slider - the track (the background bar), the thumb (the thing you drag), the fill, and then in this case the progress bar (which isn't default to the range input). I set up my own progress bar, which I then tied into with javascript to update based on when the input is changed and what value it has. I then positioned this div directly over the slider. To compensate for the issue of the slider thumb needing to being able to extend past the end of the slider (per the designs) I had to make the slider 4px wider on either side of the progress bar, then overlay some divs of the same color as the background the slider was on to hide those edges. Hacky, but it worked. Then, to actually style each element on all browsers, you basically have to disable all default behavior and styling and then build your own. I'll go over all the quirks for each browser and some general things I did to get my slider to work.

Chrome/all:


.savings-slider{
    align-items: center;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    cursor: pointer;
    height: 8px;
    width: 204px;
    position: absolute;
    bottom: 39px;
    left: 13px;
}
.savings-slider:focus { //removes default shadows and outlines when you click
   box-shadow: none;
   outline: none;
}
.savings-slider::-webkit-slider-thumb {
   -webkit-appearance: none;
   appearance: none; //removes default appearance
   width: 8px;
   height: 24px;
   border: 0;
   background: url('/wp-content/themes/analytiQs/images/slider-arrow.png'); //custom arrow for the slider thumb
   background-repeat: no-repeat;
   background-position: center;
   margin-top: 23px; //move the thumb below the slider 
   cursor: pointer;
}

.hide-edge-left{
   position: absolute;
   height: 8px;
   width: 4px;
   left: 13px;
   bottom: 39px;
   background: #242424;
}
.hide-edge-right{
   position: absolute;
   height: 8px;
   width: 4px;
   right: 13px;
   bottom: 39px;
   background: #242424;
}

Firefox:


@-moz-document url-prefix(){ //target Firefox
   .savings-slider{
      height: 6px;
      width: 210px;
      left: 9px;
      background: #fff;
   }
   .savings-slider::-moz-focus-outer{
      border: 0px;
   }

   .hide-edge-left{
      width: 8px;
      left: 9px;
   }
   .hide-edge-right{
      width: 8px;
      right: 9px;
   }
   .savings-slider::-moz-range-thumb {
      -moz-appearance: none;
      appearance: none;
      border: 0;
      background: url('/wp-content/themes/analytiQs/images/slider-arrow.png');
      background-repeat: no-repeat;
      background-position: center;
      transform: translateY(12px); //necessary on firefox to move the slider down
      cursor: pointer;
}
.savings-slider::-moz-range-track {
   -moz-appearance: none;
   appearance: none;
   opacity: 0;
}

}

Safari:
No need for any extra styling...surprising!


Internet Explorer:
Here's where things start to get messy.



@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
   .savings-slider{
      bottom: 7px;
      height: 8px;
      width: 196px; //for some reason you have to adjust the positioning and size of the slider for IE. 
      left: 17px;
   }
	
   //there doesn't seem to be a way to attach pseudo elements to the slider thumb in IE, so I needed to create a new one attached to the right side of the progress bar, but positioned below it
   .progress-bar::after{
      content:"."; //pseudo element won't show up unless you have something set as content. I just used a random character and made it transparent...
      border: 0 none;
      position: absolute;
      right: -5px;
      top: 9px;
      color: transparent; 
      pointer-events: none;
      background-color: red;
      background: url('/wp-content/themes/analytiQs/images/slider-arrow.png');
      background-repeat: no-repeat;
      background-position: center;
      height: 15px;
      width: 10px;
      background-size: cover;
      cursor: pointer;
   }
   //need to style the track specifically for IE
   input[type=range]::-ms-track {
      appearance: none;
      background: white;
      color: transparent;
      border: 0px;
   }

   input[type=range]::-ms-thumb {
      height: 10px;
      width: 10px;
      border: 0 none;
      transform: translateY(15px);
      cursor: pointer;
   }

   // need to style the lower and upper fill for IE (of course this is only supported in IE and nothing else...)
   input[type=range]::-ms-fill-lower {
      background: transparent;
      border: 0 none;
   }

   input[type=range]::-ms-fill-upper {
      background: transparent;
      border: 0 none;
   }
  
   //IE has a default tooltip that pops up. this disables it.
   input[type=range]::-ms-tooltip {
      display: none;
   }
}

Edge:


.savings-slider{
   border-bottom: 10px solid transparent; //requires some modification to compensate for weird padding and overflow rules
   bottom: 29px;
}
.progress-bar::after{ //required slightly different styling for the pseudo thumb
   content:".";
   border: 0 none;
   position: absolute;
   right: -5px;
   top: 9px;
   color: transparent;
   pointer-events: none;
   background: url('/wp-content/themes/analytiQs/images/slider-arrow.png');
   background-repeat: no-repeat;
   background-position: center;
   height: 15px;
   width: 10px;
   background-size: cover;
   cursor: pointer;
}

And finally, the jQuery:



$('.savings-slider').change(function() {
  updateValues(this.value); //function called to update values elsewhere on the page. 
  var percent = ($(this).val()*100).toFixed(0);
  document.getElementById('percent-label').innerHTML= percent+"%"; //label for the percentage
  $('.progress-bar').css("width",percent+"%"); //change width of progress bar div
});
$('.savings-slider').on('input', function() { //necessary to track changes in IE and Edge
  updateValues(this.value);
  var percent = ($(this).val()*100).toFixed(0);
  document.getElementById('percent-label').innerHTML= percent+"%";
  $('.progress-bar').css("width",percent+"%");
  // console.log("changing");
});

Well, there you go. It's a lot....but hopefully it can help if you ever find yourself in a similar situation.  Cheers, and happy hacking.

Stay in Touch!

Subscribe to our newsletter.

Solutions Architecture

browse through our blog articles

Blog Archive