Summary
I’m working on an input[type=range] that essentially looks like Chrome’s default but the thumb is green until clicked. That’s the end goal. Through a couple answers that are now buried deep in my browser history (hence lack of credit to them) I am able to get it MOSTLY working how I want.
Issue
The onLoad code works how I want it to except for one major issue: It affects all elements, not the individuals. I simply can’t figure out how to get this line:
s.textContent = `.slider::-webkit-slider-thumb { background-color: ${thumb_color} !important; } .slider:-moz-range-thumb { ${thumb_color} !important; }`;
to be set in the same manner as this line:
this.style.background = 'linear-gradient(to right, #006CBA 0%, #006CBA '+100*(this.value-1)/4 +'%, #efefef ' + 100*(this.value-1)/4 + '%, #efefef 100%)';
Supporting Code
Here are those two lines in my ‘working’ code:
let s = document.createElement("style"); document.head.appendChild(s); var range_els = document.querySelectorAll('input[type=range]'); for(let i = 0;i < range_els.length; i++) { range_els[i].addEventListener("input", () => { const slider_value = range_els[i].value; let thumb_color; if (slider_value == 0) { thumb_color = "#9CCF47"; } else { thumb_color = "#006CBA"; } //effects the style, not the individual style. :| s.textContent = `.slider::-webkit-slider-thumb { background-color: ${thumb_color} !important; } .slider:-moz-range-thumb { ${thumb_color} !important; }`; }); range_els[i].oninput = function() { this.style.background = 'linear-gradient(to right, #006CBA 0%, #006CBA '+100*(this.value-1)/4 +'%, #efefef ' + 100*(this.value-1)/4 + '%, #efefef 100%)'; }; }
<style> .slider { -webkit-appearance: none; height: 8px; border-radius: 4px; background-color: #efefef; border: 1px solid #b2b2b2; } .slider::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; border-radius: 8px; background-color: #9CCF47; cursor: pointer; } </style>
<body> <input type="range" min="1" max="5" value="0" class="slider" name="rangeInput"> </body>
Yes, I know it’s a value that’s less that min. I’m leveraging this for essentially making changing it a requirement (think like instead of 5 radio buttons for a survey). That’s also the reason I want to start with a green thumb: Green means it’s not been touched yet. This is my focus.
Thank you in advance.
Advertisement
Answer
I think you can’t write the ::-webkit-slider-thumb
, just like other pseudo-classes, as inline-style. See this thread.
But you can complete your “hack” with the <style>
element. Create one for each input and add a unique selector (e.g. id
or [name="rangeInput1"
).
var range_els = document.querySelectorAll('input[type=range]'); range_els.forEach(range_el => { let s = document.createElement("style"); document.head.appendChild(s); range_el.addEventListener("input", () => { const slider_value = range_el.value; let thumb_color; if (slider_value == 0) { thumb_color = "#9CCF47"; } else { thumb_color = "#006CBA"; } s.textContent = `.slider#${range_el.id}::-webkit-slider-thumb { background-color: ${thumb_color} !important; } .slider#${range_el.id}:-moz-range-thumb { ${thumb_color} !important; }`; }); range_el.oninput = function() { this.style.background = 'linear-gradient(to right, #006CBA 0%, #006CBA ' + 100 * (this.value - 1) / 4 + '%, #efefef ' + 100 * (this.value - 1) / 4 + '%, #efefef 100%)'; }; });
.slider { -webkit-appearance: none; height: 8px; border-radius: 4px; background-color: #efefef; border: 1px solid #b2b2b2; } .slider::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; border-radius: 8px; background-color: #9CCF47; cursor: pointer; }
<body> <input type="range" min="1" max="5" value="0" class="slider" name="rangeInput1" id="rangeInput1"> <input type="range" min="1" max="5" value="0" class="slider" name="rangeInput2" id="rangeInput2"> </body>