notsoscottishscot
notsoscottishscot

Reputation: 368

How to change the input slider thumb colour depending on value?

I'm making a site that includes a range input slider. I would like the slider thumb to change colour according to the value of the slider.

For example, if the value was 0, the thumb colour would be rgb(255, 0, 0);, if it were 100, the colour would be rgb(0, 255, 0);, and the thumb would change colour.

To be clear, I don't want something like this:

if slider_value <= 29:
  thumb_color = rgb(255, 0, 0)
else if slider_value >= 30 && slider_value <= 69:
  thumb_color = rgb(255, 255, 0)
else 
  thumb_color = rgb(0, 255, 0)

Here's the code I have so far:

.slider {
  width: 60%;
  margin: 50px auto;
  -webkit-appearance: none;
  height: 8px;
  border-radius: 4px;
  margin-bottom: 15px;
  background-color: rgb(200, 200, 200);
}

.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 10px;
  background-color: rgb(255, 120, 0);
  overflow: visible;
  cursor: pointer;
}

.slidecontainer {
  transform: translateY(-10px);
}
<div class="slidecontainer" align="center">
  <input type="range" min="0" max="100" value="50" class="slider" name="rangeInput">
</div>

Please bear in mind that I know very little Javascript, however I know many other programming languages and I know enough to understand most Javascript code. So please try to make it as simple as is possible.

How would I be able to do this effectively?

Upvotes: 7

Views: 27723

Answers (4)

tao
tao

Reputation: 90068

You're basically looking for this, right?

const input = document.querySelector('input[type="range"]');
const style = document.createElement('style');
const head = document.head || document.getElementsByTagName('head')[0];
style.type = 'text/css';
head.appendChild(style);
input.oninput = function(e) {
  const cssText = `input.slider::-webkit-slider-thumb, input.slider::-moz-range-thumb {
    background-color: rgb(${255 - 2.55*e.target.value}, ${2.55*e.target.value}, 0);
  }`;
  if (style.styleSheet) {
    style.styleSheet.cssText = cssText;
  } else {
    style.innerHTML = "";
    style.appendChild(document.createTextNode(cssText));
  }
}
.slider {
  width: 60%;
  margin: 50px auto;
  -webkit-appearance: none;
  height: 8px;
  border-radius: 4px;
  margin-bottom: 15px;
  background-color: rgb(200, 200, 200);
}

.slider::-webkit-slider-thumb, 
.slider::-moz-range-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 10px;
  background-color: rgb(128, 128, 0);
  overflow: visible;
  cursor: pointer;
}

.slidecontainer {
  transform: translateY(-10px);
}
  <div class="slidecontainer" align="center">
    <input type="range" min="0" max="100" value="50" class="slider" name="rangeInput" oninput="test">
  </div>

It's a bit trickier as ::webkit-slider-thumb is a pseudo element and (i might be wrong here) i don't think you can target it directly with JavaScript. So what I did was add a <style> tag to <head> and dynamically change its contents based on current input value, in a function triggered on input event.

It's more of a proof of concept, it can be improved by using addEventListener and it probably looks prettier in jQuery. I'll leave all that jazz to you.


Edit: As exaneta's answer points out, you have a range of options when dealing with dynamically changing colors. While I used a simple 255 > 0 for red and 0 > 255 for green in an rgb(), you might want to use exaneta's solution: hsl(${e.target.value}, 100%, 50%).

Upvotes: 6

Mister Jojo
Mister Jojo

Reputation: 22320

the simplest is to use a variable css. see : https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties

const Slider = document.querySelector('input[name=rangeInput]')

Slider.oninput =_=> Slider.style.setProperty('--SliderColor', `hsl(${Slider.value}, 100%, 50%)`)
.slidecontainer {
  transform: translateY(-10px);
  text-align: center;
}
.slider {
  --SliderColor: hsl(50, 100%, 50%);
  -webkit-appearance: none;
  width: 60%;
  margin: 50px auto;
  height: 8px;
  border-radius: 4px;
  margin-bottom: 15px;
  background-color: rgb(200, 200, 200);
}

/* --------------------------- webkit browsers */
.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 10px;
  background-color: var(--SliderColor);
  overflow: visible;
  cursor: pointer;
}
/* -------------------------- Firefox */
.slider::-moz-range-thumb { 
  -moz-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 10px;
  background-color: var(--SliderColor);
  overflow: visible;
  cursor: pointer;
}
.slider::-moz-focus-outer { border: 0; }
/* Remove dotted outline from range input element focused in Firefox */
<div class="slidecontainer">
  <input type="range" min="0" max="100" value="50" class="slider" name="rangeInput">
</div>

[edit]: adding css .slider::-moz-range-thumb (Firefox)

Upvotes: 11

enxaneta
enxaneta

Reputation: 33044

This is how I would do it: I would create a new <style> element and I woild append this element to the head. Next on input I would write a css rule that would change the thumb's color from red to green using hsl colors. I would make this css rule the text content of the new style element. I hope it helps.

let s = document.createElement("style");
document.head.appendChild(s);
itr.addEventListener("input", () => {
  s.textContent = `.slider::-webkit-slider-thumb{background-color: hsl(${itr.value}, 100%, 50%)}`
})
.slider {
  width: 60%;
  margin: 50px auto;
  -webkit-appearance: none;
  height: 8px;
  border-radius: 4px;
  margin-bottom: 15px;
  background-color: rgb(200, 200, 200);
}

.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 10px;
  background-color: hsl(50, 100%, 50%);
  overflow: visible;
  cursor: pointer;
}

.slidecontainer {
  transform: translateY(-10px);
}
<div class="slidecontainer" align="center">
  <input id="itr" type="range" min="0" max="100" value="50" class="slider" name="rangeInput">
</div>

Upvotes: 5

RegarBoy
RegarBoy

Reputation: 3521

Your post looks similar to this one: .slider::-webkit-slider-thumb needed in javascript

const range = document.getElementById("rangeInput");
var style = document.querySelector('[data="test"]');

range.addEventListener("input", () => {
   const slider_value = range.value;
   let thumb_color;
   if (slider_value <= 29) {
       thumb_color = "rgb(255, 0, 0)";
   }
   else if (slider_value >= 30 && slider_value <= 69) {
       thumb_color = "rgb(255, 255, 0)";
   }
   else {
       thumb_color = "rgb(0, 255, 0)";
   }
   style.innerHTML = `.slider::-webkit-slider-thumb { background-color: ${thumb_color} !important; } .slider:-moz-range-thumb {  ${thumb_color} !important; }`;
});
.slider {
    width: 60%;
    margin: 50px auto;
    -webkit-appearance: none;
    height: 8px;
    border-radius: 4px;
    margin-bottom: 15px;
    background-color: rgb(200, 200, 200);
}

.slider::-webkit-slider-thumb {
   -webkit-appearance: none;
    width: 18px;
    height: 18px;
    border-radius: 10px;
    background-color: rgb(255, 120, 0);
    overflow: visible;
    cursor: pointer;
    transition: all 1s ease;
        
}

.slidecontainer {
    transform: translateY(-10px);
}
<style data="test" type="text/css"></style>

<div class="slidecontainer" align="center">
    <input id="rangeInput" type="range" min="0" max="100" value="50" class="slider" name="rangeInput">
</div>

Upvotes: 1

Related Questions