I am trying to display the value of a range item centered above the thumb. This works quite well by reading out the value and positioning the element above the range element as a percentage of its clientWidth
.
There is however a growing offset away from the middle (see pictures) which causes the value not to be centered on the thumb. I am convinced that this is caused because the thumb actually moves less than the clientWidth
because of the size of the thumb itself and maybe some room around the track.
How do I take this into account?
The JSFiddle can be found here: https://jsfiddle.net/jd4kncuk/
var myRange = document.querySelector('#myRange');
var myValue = document.querySelector('#myValue');
var off = myRange.clientWidth / (parseInt(myRange.max) - parseInt(myRange.min));
var px = ((myRange.valueAsNumber - parseInt(myRange.min)) * off) - (myValue.clientWidth / 2);
myValue.style.left = px + 'px';
myValue.style.top = -myRange.offsetHeight - 5 + 'px';
myValue.innerHTML = myRange.value;
myRange.oninput = function() {
let px = ((myRange.valueAsNumber - parseInt(myRange.min)) * off) - (myValue.clientWidth / 2);
myValue.innerHTML = myRange.value;
myValue.style.left = px + 'px';
};
<div style="position:relative; margin:auto; width:90%; margin-top:80px;">
<output style="position:absolute; min-width:100px; text-align: center;" id="myValue"></output>
<input type="range" id="myRange" min="0" max="200" step="5" style="width:80%" value="80">
</div>
Check this For More Using CSS: link
var myRange = document.querySelector('#myRange');
var myValue = document.querySelector('#myValue');
var thumbWidth = 18;
var off = (myRange.clientWidth - thumbWidth) / (parseInt(myRange.max) - parseInt(myRange.min));
var px = ((myRange.valueAsNumber - parseInt(myRange.min)) * off) - (myValue.clientWidth / 2) + (thumbWidth / 2);
myValue.style.left = px + 'px';
myValue.style.top = -myRange.offsetHeight - 5 + 'px';
myValue.innerHTML = myRange.value;
myRange.oninput = function() {
let px = ((myRange.valueAsNumber - parseInt(myRange.min)) * off) - (myValue.clientWidth / 2) + (thumbWidth / 2);
myValue.innerHTML = myRange.value;
myValue.style.left = px + 'px';
};
<div style="position:relative; margin:auto; width:90%; margin-top:80px;">
<output style="position:absolute; min-width:100px; text-align: center;" id="myValue"></output>
<input type="range" id="myRange" min="0" max="200" step="5" style="width:80%" value="80">
</div>
I think I've solved it. The issue was caused by the width of the thumb not being taken into account. The thumb doesn't move across the slider 100%, but rather 100% - ~15px. This way the thumb never overlaps the sides of the slider. Note that the ~15px width for a slider thumb is taken from chrome, in other browsers this could be different.
To take this into account when positioning the value display we need to offset it by a percentage of half of the width of the thumb, ranging from +7.5px to -7.5px. Here is an updated fiddle https://jsfiddle.net/crf96bw7/1/ that shows it working. I have added an extra bit of markup to help show the centre position of the value container.
var myRange = document.querySelector('#myRange');
var myValue = document.querySelector('#myValue');
var myValueInner = document.querySelector('#myValueInner');
var buttonWidth = 15;
var range = parseInt(myRange.max) - parseInt(myRange.min)
var centerDotOffset = (myRange.valueAsNumber / range - 0.5) * buttonWidth;
var off = myRange.clientWidth / range;
var px = ((myRange.valueAsNumber - parseInt(myRange.min)) * off) - (myValue.clientWidth / 2) - centerDotOffset;
myValue.style.left = px + 'px';
myValue.style.top = -myRange.offsetHeight - 5 + 'px';
myValueInner.innerHTML = myRange.value;
myRange.oninput = function() {
var centerDotOffset = (myRange.valueAsNumber / range - 0.5) * buttonWidth
let px = ((myRange.valueAsNumber - parseInt(myRange.min)) * off) - (myValue.clientWidth / 2) - centerDotOffset;
myValueInner.innerHTML = myRange.value;
myValue.style.left = px + 'px';
};
#container {
position: relative;
box-sizing: border-box;
margin: 0 auto;
width: 90%;
margin-top: 80px;
}
#myRange {
width: 100%;
margin: 0;
}
#myValue {
background: black;
}
#myValue #myValueInner {
width: 50%;
background: gold;
}
<div id="container">
<output style="position:absolute; min-width:100px; text-align: center;" id="myValue"><div id="myValueInner">
</div></output>
<input type="range" id="myRange" min="0" max="200" step="5" value="150">
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With