<div class="info">Vertical cross-browser supported input range html elements, no library dependency, no transform rotate.</div>
<div class="container">
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar"></div>
<div class="range-slider__thumb"></div>
</div>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar theme1"></div>
<div class="range-slider__thumb"></div>
</div>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar theme2"></div>
<div class="range-slider__thumb"></div>
</div>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar theme3"></div>
<div class="range-slider__thumb"></div>
</div>
</div>
// Credit to Ana Tudor
// The mixins are based on Ana Tudor's pen codepen.io/thebabydino/pen/pvLPOQ
$slider-track-thickness: 8px;
$slider-thumb-size: 30px;
$slider-height: 300px;
$slider-width: 40px;
$color-theme: #3D3D4A;
$color-track: #343440;
@mixin track {
border: none;
background: $color-track;
width: $slider-track-thickness;
border-color: $color-track;
border-radius: 10px;
box-shadow: 0 0 0 2px $color-theme;
}
@mixin thumb {
// This seemed buggy to make it work pretty for all modern browsers.
// A dummy visual UI thumb has been added.
width: $slider-thumb-size;
height: $slider-thumb-size;
opacity: 0;
}
*, *:before,*:after{
box-sizing: border-box;
}
html,
body{
height: 100%;
}
body{
margin: 0;
background: $color-theme;
color: white;
min-height: 400px;
font-family: sans-serif;
}
.info{
position: absolute;
top: 0;
left: 0;
padding: 10px;
opacity: .5;
}
.container{
//outline: 1px dashed hotpink; // debug
padding-top: 40px;
position: relative;
display: inline-block;
top: 100%;
left: 50%;
transform: translate(-50%, -100%);
padding-bottom: 20px;
@media(min-height: 500px){
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
padding-bottom: 0;
}
}
.range-slider {
display: inline-block;
width: $slider-width;
position: relative;
text-align: center;
height: $slider-height;
max-height: 100%;
//box-shadow: 0 0 0 1px deeppink; // debug
&:before{
// Display value
position: absolute;
top: -2em;
left: .5em;
content: attr(data-slider-value) '%';
color: white;
font-size: 90%;
}
&__thumb{
position: absolute;
left: $slider-width/2 - $slider-thumb-size/2;
width: $slider-thumb-size;
height: $slider-thumb-size;
line-height: $slider-thumb-size;
background: white;
color: #777;
font-size: 50%;
box-shadow: 0 0 0 4px $color-theme;
border-radius: 50%;
pointer-events: none;
}
&__bar{
left: $slider-width/2 - $slider-track-thickness/2;
bottom: 0;
position: absolute;
background: linear-gradient(dodgerblue,blue);
pointer-events: none;
width: $slider-track-thickness;
border-radius: 10px;
}
input[type=range][orient=vertical]
{
//outline: 1px dashed white; // debug
position: relative;
margin: 0;
height: 100%;
width: 100%;
display: inline-block;
position: relative;
writing-mode: bt-lr; // IE
-webkit-appearance: slider-vertical; // webkit
&::-webkit-slider-runnable-track,
&::-webkit-slider-thumb {
-webkit-appearance: none;
}
&::-webkit-slider-runnable-track {
@include track;
}
&::-moz-range-track {
@include track;
}
&::-ms-track {
@include track;
color: transparent;
height: 100%;
}
&::-ms-fill-lower,
&::-ms-fill-upper,
&::-ms-tooltip {
display: none;
}
&::-webkit-slider-thumb {
@include thumb;
}
&::-moz-range-thumb {
@include thumb;
}
&::-ms-thumb {
@include thumb;
}
}
}
.theme1{
background: linear-gradient(pink,deeppink);
}
.theme2{
background: linear-gradient(tomato,red);
}
.theme3{
background: linear-gradient(yellow,orange);
}
View Compiled
let app = (() => {
function updateSlider(element) {
if (element) {
let parent = element.parentElement,
lastValue = parent.getAttribute('data-slider-value');
if (lastValue === element.value) {
return; // No value change, no need to update then
}
parent.setAttribute('data-slider-value', element.value);
let $thumb = parent.querySelector('.range-slider__thumb'),
$bar = parent.querySelector('.range-slider__bar'),
pct = element.value * ((parent.clientHeight - $thumb.clientHeight) / parent.clientHeight);
$thumb.style.bottom = `${pct}%`;
$bar.style.height = `calc(${pct}% + ${$thumb.clientHeight/2}px)`;
$thumb.textContent = `${element.value}%`;
}
}
return {
updateSlider: updateSlider
};
})();
(function initAndSetupTheSliders() {
const inputs = [].slice.call(document.querySelectorAll('.range-slider input'));
inputs.forEach(input => input.setAttribute('value', '50'));
inputs.forEach(input => app.updateSlider(input));
// Cross-browser support where value changes instantly as you drag the handle, therefore two event types.
inputs.forEach(input => input.addEventListener('input', element => app.updateSlider(input)));
inputs.forEach(input => input.addEventListener('change', element => app.updateSlider(input)));
})();
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.