Search code examples
htmlcssinput-type-range

CSS - styling input type range


I have a range input like so:

.volume{
    -webkit-appearance:none;
    width:100px;
    background:transparent;
}
.volume:focus{
    outline:none;
}
.volume::-webkit-slider-runnable-track{
    height:5px;
    cursor:pointer;
    background:Black;
    border:0.5px solid DimGrey;
    border-radius:5px;
}
.volume::-webkit-slider-thumb{
    -webkit-appearance:none;
    border:1px solid #444;
    width:30px;
    height:16px;
    text-align:center;
    margin-top:-5.5px;
    background:url("https://prototype.demixr.com/media/slider.png") center no-repeat;
}
<input class="d-inline-block volume" type="range" name="volume0" id="volume0" data-id="0" min="0" max="1" value="0.5" step="0.01">
<br />
<img src="https://prototype.demixr.com/media/ruler.png" alt="slider steps" class="levels_steps">

Is it possible to get the thumb image to overflow the track so that the center of the image lines up with the ruler underneath when it is at the extreme of either side?


Solution

  • Basically what you do is shrink the volume scale below the thumb to fit the start and end position. Then add a margin on the left to push the scale image to the starting position. Then exchange the background of the range slider itself to use a gradient with opacity on the edges (left and right) to make sure the slider knob moves to the end positions of the slider and does not still show some black pixels.

    The code should now work in Chrome and Firefox.

    Code:

    .volume {
      -webkit-appearance: none;
      width: 120px;
      background: transparent;
    }
    
    .volume:focus {
      outline: none;
    }
    
    .volume::-webkit-slider-runnable-track {
      height: 5px;
      cursor: pointer;
      background: rgba(0, 0, 0, 0);
      background: -moz-linear-gradient(left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      background: -webkit-gradient(left top, right top, color-stop(0%, rgba(0, 0, 0, 0)), color-stop(12%, rgba(0, 0, 0, 0)), color-stop(12%, rgba(0, 0, 0, 1)), color-stop(88%, rgba(0, 0, 0, 1)), color-stop(88%, rgba(0, 0, 0, 0)), color-stop(100%, rgba(0, 0, 0, 0)));
      background: -webkit-linear-gradient(left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      background: -o-linear-gradient(left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      background: -ms-linear-gradient(left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#000000', endColorstr='#000000', GradientType=1);
    }
    
    .volume::-webkit-slider-thumb {
      -webkit-appearance: none;
      border: 1px solid #444;
      width: 30px;
      height: 16px;
      text-align: center;
      margin-top: -5.5px;
      background: url("https://prototype.demixr.com/media/slider.png") center no-repeat;
    }
    
    input[type=range]::-moz-range-track {
      height: 5px;
      cursor: pointer;
      background: rgba(0, 0, 0, 0);
      background: -moz-linear-gradient(left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      background: -webkit-gradient(left top, right top, color-stop(0%, rgba(0, 0, 0, 0)), color-stop(12%, rgba(0, 0, 0, 0)), color-stop(12%, rgba(0, 0, 0, 1)), color-stop(88%, rgba(0, 0, 0, 1)), color-stop(88%, rgba(0, 0, 0, 0)), color-stop(100%, rgba(0, 0, 0, 0)));
      background: -webkit-linear-gradient(left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      background: -o-linear-gradient(left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      background: -ms-linear-gradient(left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 1) 12%, rgba(0, 0, 0, 1) 88%, rgba(0, 0, 0, 0) 88%, rgba(0, 0, 0, 0) 100%);
      filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#000000', endColorstr='#000000', GradientType=1);
    }
    
    input[type=range]::-moz-range-thumb
    {
      -webkit-appearance: none;
      border: 1px solid #444;
      width: 30px;
      height: 16px;
      text-align: center;
      margin-top: -5.5px;
      background: url("https://prototype.demixr.com/media/slider.png") center no-repeat;
    }
    
    .levels_steps {
      width: 90px;
      margin-left: 17px;
    }
    <input class="d-inline-block volume" type="range" name="volume0" id="volume0" data-id="0" min="0" max="1" value="0.5" step="0.01">
    <br />
    <img src="https://prototype.demixr.com/media/ruler.png" alt="slider steps" class="levels_steps">

    In normal cases I would have assigned the CSS rules to both Firefox and Chrome in one rule (.volume::-webkit-slider-runnable-track, .input[type=range]::-moz-range-track { ... } but this either made the changes disappear in Chrome or Firefox so I duplicated it. Might be due to the browser-specific prefixes -moz and -webkit.