Get computed value of CSS variable that uses an ex

2020-03-21 10:14发布

问题:

In JavaScript, you can get the value of a CSS variable using getPropertyValue(property). This function is useful for retrieving variables declared in the :root block.

:root {
    --example-var: 50px;
}

However, if this variable expression contains a function like calc, the getPropertyValue call returns the expression as text rather than computing it, even when using getComputedStyle.

:root {
    --example-var: calc(100px - 5px);
}

How can I get the computed value of a CSS variable that uses a CSS function like calc?

See the example below:

let div = document.getElementById('example');
console.log(window.getComputedStyle(div).getPropertyValue('--example-var'))
:root {
  --example-var: calc(100px - 5px);
}
<div id='example'></div>

回答1:

Technically you cannot because the computed value is not static and will depend on other properties. In this case it's trivial since we are dealing with pixel value but imagine the case where you will have percentage value. Percentage is relative to other properties so we cannot compute it until it's used with var(). Same logic if we use unit like em, ch, etc

Here is a simple example to illustrate:

let div = document.getElementById('example');
console.log(window.getComputedStyle(div).getPropertyValue('--example-var'))
console.log(window.getComputedStyle(div).getPropertyValue('font-size'))
console.log(window.getComputedStyle(div).getPropertyValue('width'))
console.log(window.getComputedStyle(div).getPropertyValue('background-size'));
:root {
  --example-var: calc(100% + 5px - 10px);
}
#example {
  font-size:var(--example-var);
  width:var(--example-var);
  background-size:var(--example-var);
}
<div id='example'>some text</div>

It's important to note the last case, where background-size has a special behavior when combining percentage and pixel value. You can also clearly see in the first case that the browser will not even compute the 5px - 10px and will do it only when using var().


In case you know that the calc() will only be used with pixel values, you can simply apply it to any property and read it. It will work since the computed value will always be evaluted the same whataver the property is:

let div = document.getElementById('example');
console.log(window.getComputedStyle(div).getPropertyValue('--example-var'))
console.log(window.getComputedStyle(div).getPropertyValue('font-size'))
console.log(window.getComputedStyle(div).getPropertyValue('width'))
console.log(window.getComputedStyle(div).getPropertyValue('background-size'));
console.log(window.getComputedStyle(div).getPropertyValue('background-color'));
:root {
  --example-var: calc(100px - 10px);
  --test:var(--example-var)
}
#example {
  font-size:var(--example-var);
  width:var(--example-var);
  background-size:var(--example-var);
  background-color:var(--example-var);
}
<div id='example'></div>

Of course you need to make sure to consider a property that expect a pixel value or you will have an invalid value (like with background in the previous example).



回答2:

well a wacky way of doing this is adding


:root {
  --example-var: calc(100px - 5px);
}

#var-calculator {
    // can be fetched through .getBoundingClientRect().width
    width: var(--example-var); 

    // rest of these just to make sure this element
    // does not interfere with your page design.
    opacity: 0;
    position: fixed;
    z-index: -1000;
}


 <custom-element>
  <div id="var-calculator"></div>
</custom-element>


const width = document.getElementById('var-calculator').getBoundingClientRect().width

I don't know if this is applicable for your use case, but I just tested it and it works.



回答3:

Value will get computed when assigned (including programmatically) to some real property:

const div = document.getElementById('example');
div.style.width = 'var(--example-var)';
console.log(window.getComputedStyle(div).getPropertyValue('width'));
:root {
  --example-var: calc(100px - 5px);
}
<div id='example'></div>