This is an odd request; However, what would be the best method to display the value of an HTML5 range-slider on the thumb of the slider?! the thumb will be animated onLoad so it must follow the thumb; moreover, this will be displayed for iPad
EXAMPLE:
<input class="range-consideration" type="range" name="points" min="1" max="10" ng-model="rangeConsiderations">
This is an odd request; However, what would be the best method to display the value of an HTML5 range-slider on the thumb of the slider?! the thumb will be animated onLoad so it must follow the thumb; moreover, this will be displayed for iPad
EXAMPLE:
<input class="range-consideration" type="range" name="points" min="1" max="10" ng-model="rangeConsiderations">
Share
Improve this question
edited Nov 20, 2017 at 17:44
Erol Aliyev
652 silver badges8 bronze badges
asked May 26, 2014 at 8:06
John AbrahamJohn Abraham
18.8k36 gold badges132 silver badges240 bronze badges
0
6 Answers
Reset to default 4I too have had a lot of trouble figuring out a way to display the value of a range slider on its thumb. When working this out, I thought of three methods:
1. Combining multiple pseudo-elements
(Spoiler: Doesn't work - Read BoltClock's comment on the accepted answer of this thread)
body {
--thumbNumber: "5"; // updates on slider input via JavaScript function
}
#slider {
-webkit-appearance: none;
outline: none;
width: 400px;
height: 3px;
background-color: #555;
}
#slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 30px;
height: 30px;
cursor: pointer;
background: #5a5;
}
#slider::-webkit-slider-thumb::before { // doesn't work (refer to above link)
content: var(--thumbNumber);
}
<body>
<input type="range" id="slider" value="5" min="1" max="10" />
</body>
window.onload = function () {
var slider = document.getElementById("slider");
slider.addEventListener("input", function () {
document.body.style.setProperty("--thumbNumber", "'" + this.value + "'");
});
// whenever this element receives input, change the value of --thumbNumber to this element's value
}
I thought I was pretty clever by using CSS variables to avoid the problem of not being able to directly change the properties of a pseudo-element in JavaScript. I learned, however, that this approach cannot work because you cannot use more than one pseudo-element selector in the same selection. (Refer to above link).
2. Dynamically changing the thumb's content
property with JavaScript
This method is very similar to the previous one. The only difference is in the CSS. (Spoiler: This method also didn't work)
#slider::-webkit-slider-thumb {
content: var(--thumbNumber);
}
The JavaScript is the exact same as before. The idea is that the event listener attached to the slider element listens for input events, and reacts by changing the value of the CSS variable --thumbNumber
. This causes the content
property of the thumb to update and display the change. This doesn't work, however, because CSS doesn't seem to let you change the content
property of the thumb.
3. Using CSS Variables and... images...
This is basically as bad as it gets when it comes to dirty solutions. This is completely unscalable, but it's only a little bit godawful when working with less than 10 numbers on an input range.
For this example, I made 10 png files in photoshop in about 10 minutes. Each file is a 30px by 30px image of a number on a transparent background. Their filenames are 1.png, 2.png, 3.png, and so on until 10.png. Each file is stored in a folder called png. This folder is located in the same folder as the html document.
body {
--sliderImage: url("png/5.png");
}
#slider::-webkit-slider-thumb {
background-image: var(--sliderImage);
}
window.onload = function () {
var slider = document.getElementById("slider");
slider.addEventListener("input", function () {
document.body.style.setProperty("--sliderImage", "url('png/" + this.value + ".png')");
});
}
This example is obviously terrible in so many ways, but it's all I've been able to try that has worked.
Basically, this makes it so that when the slider element receives input, the value of the CSS variable --sliderImage
is changed to, for example, url('png/6.png')
when the slider thumb is dragged onto the value 6. This causes the background-image
property of the thumb to update to a picture that correctly represents the value of the slider.
I am still searching for and trying to come up with an actual, reasonable answer to this problem. It puzzles me how such a seemingly simple task can, in reality, be very layered and difficult. I'll edit my answer as soon as I figure it out.
You cannot display value in the thumb but you can attach a bubble to the thumb which will contain and display the value as you slide. Refer to this detailed article Show slider value.
Here's a demo.
- You create a div that will follow the handle.
- Then, every time the handle is moved/changed (onslide/onchange), put the value of the handler to the div and also modify the current position of the div the same with the handle so that it will follow the handle.
or maybe, if possible, on onchange method of the slider get the id of the handle and just put
$('#handle').text($(this).val());
I'm just giving you ideas here. I'm sure there will be better answers.
Webkit allows you to target the thumb with css :
.range-consideration::-webkit-slider-thumb::before {
content: "test";
}
That will print test
on the thumb. However, using attr(value) doesn't seem to work, so I don't know how to show the value. Maybe you can find a way by playing with css variables and changing it with javascript.
The equivalent for other browsers are ::-moz-range-thumb
and ::-ms-thumb
.
EDIT : This is really (really !) a dirty way, but it works and it's doable as long as you have a relatively limited range of values.
HTML :
<input class="range-consideration" type="range" min="1" max="10" value="3" onchange="this.setAttribute('value', this.value);" />
CSS :
.range-consideration[value="1"]::-webkit-slider-thumb::before { content: "1"; color: black; }
.range-consideration[value="2"]::-webkit-slider-thumb::before { content: "2"; color: black; }
.range-consideration[value="3"]::-webkit-slider-thumb::before { content: "3"; color: black; }
.range-consideration[value="4"]::-webkit-slider-thumb::before { content: "4"; color: black; }
.range-consideration[value="5"]::-webkit-slider-thumb::before { content: "5"; color: black; }
.range-consideration[value="6"]::-webkit-slider-thumb::before { content: "6"; color: black; }
.range-consideration[value="7"]::-webkit-slider-thumb::before { content: "7"; color: black; }
.range-consideration[value="8"]::-webkit-slider-thumb::before { content: "8"; color: black; }
.range-consideration[value="9"]::-webkit-slider-thumb::before { content: "9"; color: black; }
.range-consideration[value="10"]::-webkit-slider-thumb::before { content: "10"; color: black; }
This "workaround" has lots and lots of lipstick on it... but it is possible with a automated derivation of Sebastien C. answer http://codepen.io/anon/pen/xbQoLj
$(document).ready(function() {
var $daFoo = $('#foo');
var rule = "<style>";
// get mix & max of the slider
for(var i= parseInt($daFoo.attr("min")); i<= parseInt($daFoo.attr("max")); i++)
// for each value possible in this SINGLE!! slider - push a rule
rule += 'input[type=range][data-value="' + i + '"]::-webkit-slider-thumb::after { content: "' + i + '"; }';
$('head').append(rule + "</style>");
$daFoo.on('input', function() { $daFoo.attr('data-value', $daFoo.val()) });
});
I found one method which works good. I used react. For this need styled-components library https://styled-components.com/ (or any other way to get pseudo-element in jsx file). Also we will use svg image for background-image in pseudo-element and show there amount above where is slider-thumb.
Here you can prepare your svg image https://yoksel.github.io/url-encoder/ or
you can use my
<svg xmlns='http://www.w3.org/2000/svg' height='40' width='20'><circle cx='6' cy='20' r='6' fill='black'/><text x='2' y='12' fill='black'>2</text></svg>
Put it in https://yoksel.github.io/url-encoder/ and change that you need.
for getting input value use useState and send it as props in styled.input
import { useState } from "react";
import styled from "styled-components";
const RangeInput = styled.input`
-webkit-appearance: none;
height: 2px;
background: black;
width: 260px;
&::-webkit-slider-thumb {
-webkit-appearance: none;
height: 40px;
width: 20px;
cursor: pointer;
background-image: ${(props) =>
`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='40' width='20'%3E%3Ccircle cx='6' cy='20' r='6' fill='black'/%3E%3Ctext x='${
props.amount >= 10 ? -1 : 2
}' y='12' fill='black'%3E${props.amount}%3C/text%3E%3C/svg%3E");`};
}
`;
export const CalculateRangeInput = () => {
const [amount, setAmount] = useState("2");
return (
<RangeInput
onChange={(e) => setAmount(e.target.value)}
defaultValue={2}
amount={Number(amount)}
type="range"
/>
);
};
result which i got through this way: