4

I have a full working CodePen here showing the problem. I'm using CSS custom properties like so:

:root {
  --global-primary-colour-hue: 211;
  --global-primary-colour-saturation: 100%;
  --global-primary-colour-lightness: 50%;
  --global-primary-colour-opacity: 1;
  --global-primary-colour: hsla(
    var(--global-primary-colour-hue),
    var(--global-primary-colour-saturation),
    var(--global-primary-colour-lightness),
    var(--global-primary-colour-opacity));
}

.box {
  background-color: var(--global-primary-colour);
  height: 100px;
  width: 100px;
}

Then I've set up a range slider and box to display the colour in my HTML:

<input id="hue-range" value="0" type="range" min="0" max="360">

<div class="box"></div>

Finally I want to use the range slider to drive the --global-primary-colour-hue property. I can get this to work like so:

var element = document.getElementById("hue-range");
element.onchange = function(){
  document.body.style.setProperty(
    "--global-primary-colour-hue", 
    this.value.toString());

  // Why does the box stop changing colour when I comment out this line?
  document.body.style.setProperty(
    "--global-primary-colour",
    "hsla(var(--global-primary-colour-hue),var(--global-primary-colour-saturation),var(--global-primary-colour-lightness),var(--global-primary-colour-opacity))");
}

My question is, why do I have to set the --global-primary-colour property? When I uncomment that last line, the colour in the box no longer changes.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Muhammad Rehan Saeed
  • 35,627
  • 39
  • 202
  • 311

1 Answers1

3

In your script, you're setting the custom properties on the body element. However, in your stylesheet, your custom properties are all (as usual) specified for :root, the html element. So the value of --global-primary-colour-hue is unchanged for :root, and the value of --global-primary-colour in turn remains unchanged. This unchanged value then gets inherited by body and .box — the new value of --global-primary-colour-hue ends up never getting used.

Setting the property for document.documentElement in your script, or changing the CSS rule to target body instead, allows your code to work correctly without needing that last line:

var element = document.getElementById("hue-range");
element.onchange = function(){
  document.documentElement.style.setProperty(
    "--global-primary-colour-hue", 
    this.value);
}
:root {
  --global-primary-colour-hue: 211;
  --global-primary-colour-saturation: 100%;
  --global-primary-colour-lightness: 50%;
  --global-primary-colour-opacity: 1;
  --global-primary-colour: hsla(
    var(--global-primary-colour-hue),
    var(--global-primary-colour-saturation),
    var(--global-primary-colour-lightness),
    var(--global-primary-colour-opacity));
}

.box {
  background-color: var(--global-primary-colour);
  height: 100px;
  width: 100px;
}
<input id="hue-range" value="0" type="range" min="0" max="360">

<div class="box"></div>
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 2
    I think it's a good practise to avoid any evalutation at the root level. Doing so will oblige us to always change the properties at root level and we lose all kind of flexibility in case we need to deal with different elements where we want a different value each time. All will inherit the same value and we can do nothing. – Temani Afif Sep 06 '18 at 09:19
  • 1
    @Temani Afif: I agree. If I had the energy and motivation to, I'd write in depth about that... – BoltClock Sep 06 '18 at 09:21