Style lower and upper fill in HTML5 range input

41,131

Solution 1

First of all, read the article Styling Cross-Browser Compatible Range Inputs with CSS by Daniel Stern. His idea is to make the input invisible and then apply the custom styles.

He also developed an excellent online tool named randge.css in which you select the style preset and parameters and get auto generated CSS code like the following one:

input[type=range] {
  -webkit-appearance: none;
  margin: 10px 0;
  width: 100%;
}
input[type=range]:focus {
  outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
  width: 100%;
  height: 12.8px;
  cursor: pointer;
  animate: 0.2s;
  box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
  background: #ac51b5;
  border-radius: 25px;
  border: 0px solid #000101;
}
input[type=range]::-webkit-slider-thumb {
  box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
  border: 0px solid #000000;
  height: 20px;
  width: 39px;
  border-radius: 7px;
  background: #65001c;
  cursor: pointer;
  -webkit-appearance: none;
  margin-top: -3.6px;
}
input[type=range]:focus::-webkit-slider-runnable-track {
  background: #ac51b5;
}
input[type=range]::-moz-range-track {
  width: 100%;
  height: 12.8px;
  cursor: pointer;
  animate: 0.2s;
  box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
  background: #ac51b5;
  border-radius: 25px;
  border: 0px solid #000101;
}
input[type=range]::-moz-range-thumb {
  box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
  border: 0px solid #000000;
  height: 20px;
  width: 39px;
  border-radius: 7px;
  background: #65001c;
  cursor: pointer;
}
input[type=range]::-ms-track {
  width: 100%;
  height: 12.8px;
  cursor: pointer;
  animate: 0.2s;
  background: transparent;
  border-color: transparent;
  border-width: 39px 0;
  color: transparent;
}
input[type=range]::-ms-fill-lower {
  background: #ac51b5;
  border: 0px solid #000101;
  border-radius: 50px;
  box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-fill-upper {
  background: #ac51b5;
  border: 0px solid #000101;
  border-radius: 50px;
  box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-thumb {
  box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
  border: 0px solid #000000;
  height: 20px;
  width: 39px;
  border-radius: 7px;
  background: #65001c;
  cursor: pointer;
}
input[type=range]:focus::-ms-fill-lower {
  background: #ac51b5;
}
input[type=range]:focus::-ms-fill-upper {
  background: #ac51b5;
}

body {
  padding: 30px;
}
<input type="range">

Yes, with CSS only it's possible on IE only, but if you don't mind to add some scripting it can be simulated with linear gradient. See the following sample: codepen.io/ryanttb/pen/fHyEJ

Solution 2

There's a (newish?) pseudo-element for Firefox that styles (what IE calls) the 'lower' part of the range input. According to the documentation:

The ::-moz-range-progress CSS pseudo-element represents the portion of the "track" (the groove in which the indicator aka thumb slides) of an <input> of type="range", which corresponds to values lower than the value currently selected by the thumb.

For the upper track, you still use (per Alexander Dayan's answer) ::-moz-range-track.

I just discovered and tried it today; works pretty well.

Solution 3

At this stage there is still no option for native implementation of -ms-fill-lower or -moz-fill-lower in Chrome. Manipulating the range input element with RangeSlider.js was not an option so I used the tweaking technique with CSS linear Gradients and little bit of javascript to fire css changes on input range thumb movement Hope this helps someone check example on Codepen

Solution 4

I'm using this solution inspired by Noah Blon. It uses a box shadow based on view width (100vw is the max width of the slider), and constrains with overflow:hidden. I'm using a round thumb, so subtracted half the thumb width from the 100vw, otherwise the box shadow creeps over the other side of the thumb.

css

.wb-PKR-slider {
    -webkit-appearance:none;
    appearance:none;
    margin:5px;
    width:calc(100% - 10px);
    width:-webkit-calc(100% - 10px);
    height:25px;
    outline:none;
    background:bisque;
    border-radius:12px;   
    overflow: hidden;
}
.wb-PKR-slider::-webkit-slider-thumb {
    -webkit-appearance:none;
    appearance:none;
    width:25px;
    height:25px;
    background:sienna;
    box-shadow: -100vw 0 0 calc(100vw - 12px) peru;
    cursor:pointer;
    border-radius: 50%; 
}

html

<input type="range" min="0" max="150" value="25" class="wb-PKR-slider" id="wb-PKR-chip-count">

(fyi bisque, sienna and peru are all named css colours)

Solution 5

i'm using the following code which was based on the link provided by A. Dayan. Taking note of the min-max values and being specifically for webkit, also hiding that it is actually a gradient.

<html>
<head>
    <title>A styled slider</title>
    <script src="js/jquery-1.10.2.min.js" type="text/javascript"></script>

    <style type="text/css">
        input[type='range'] {
            -webkit-appearance: none;
            width: 100%;
            border-radius: 4px;
            height: 5px;
            border-color: #1f1f1f; 
            border-style: solid; 
            border-width: 1px;
            background: -webkit-linear-gradient(left, green 0%, green 50%, black 50%);
        }

        input[type='range']::-webkit-slider-thumb {
            -webkit-appearance: none !important;
            -webkit-border-radius: 2px;
            background-color: blue;
            height: 21px;
            width: 9px;
        }

        input[type=range]:focus {
            outline: none; 
        }
    </style>


</head>
<body>
    <div>
      <input type="range" value="75" min="100" max="300" />
    </div>
    <script type="text/javascript" >
        $('input[type="range"]').on('input', function () {
            var percent = Math.ceil(((this.value - this.min) / (this.max - this.min)) * 100);
            console.log(this.min);
            $(this).css('background', '-webkit-linear-gradient(left, green 0%, green ' + percent + '%, black ' + percent + '%)');
        });
    </script>
</body>
</html>
Share:
41,131
Ben Cook
Author by

Ben Cook

I'm an energetic manager who loves coaching ambitious software engineers and fast-paced, Agile development teams. Formerly, I was a software engineer, educator, published author, student of ancient political philosophy, and Peace Corps volunteer. I have strong communication and team leadership skills and a history of building relationships of trust and frankness with employees and coworkers.

Updated on August 21, 2020

Comments

  • Ben Cook
    Ben Cook over 3 years

    As explained here, IE allows styling of the lower and upper fill or track regions in CSS as follows:

    /* The following only affects the range input in IE */
    
    input[type="range"]::-ms-fill-lower {
      background-color: red; 
    }
    
    input[type="range"]::-ms-fill-upper {  
      background-color: blue;
    }
    <input type="range">

    Does anyone know of a way to apply different styles to the upper and lower tracks of a range input in Firefox, Chrome, etc. using CSS or any JS library?

    UPDATE:

    As pointed out by Wilson F, this is now supported in Firefox:

    /* The following only affects the range input in FF */
    
    input[type="range"]::-moz-range-progress {
      background-color: red; 
    }
    
    input[type="range"]::-moz-range-track {  
      background-color: blue;
    }
    <input type="range">  
  • Ben Cook
    Ben Cook about 9 years
    thank you. This is very helpful, but unfortunately, it doesn't answer my main question. I want to apply different styles to the regions of the track to the left and to the right of the "thumb". I'm not sure if this is possible outside of IE.
  • Alexander Dayan
    Alexander Dayan about 9 years
    Yes, with CSS only it's possible on IE only, but if you don't mind to add some scripting it can be simulated with linear gradient. See the following sample: codepen.io/ryanttb/pen/fHyEJ
  • Ben Cook
    Ben Cook about 9 years
    Very nice. Thank you.
  • Milad Rahimi
    Milad Rahimi about 8 years
    It just shows how to set color for the range not lower and upper as mentioned in the question
  • user3162879
    user3162879 about 6 years
    Can I get the AngularJS version please?
  • Duplich
    Duplich almost 6 years
    Unfortunately I have no more access to this code. It is left behind in the old company I did this for :/
  • V. Rubinetti
    V. Rubinetti over 5 years
    This is a good css-only solution, even if it feels very hack-y. Note that on the lower portion of the slider, the fill color will be cutoff in a rectangular fashion, so this will not work if you want your track to have a border radius.
  • graup
    graup over 3 years
    This is a great trick. You can also use CSS variables to set the value in a more efficient way.