JS: get the "real" value of CSS Custom Property

321 Views Asked by At

I know that this question seems to be asked 1 million time but here there is a little subtility.

Imagine I have some CSS Custom Property like this:

/* Yes the colors are terrible in this exemple, I know */
:root {
    --color_1: salmon;
    --color_2: green;
}
.foo {
    background-color: var(--color_1, var(--color_2, black));
    color: var(--color_2, var(--color_1, white));
}
.foo.inverted {
    background-color: var(--color_2, var(--color_1, white));
    color: var(--color_1, var(--color_2, black));
}

And now in JS I want to get the value of the property "color" of ".foo". With something like this it's pretty easy:

const firstFoo = document.querySelector('.foo');
const gs = getComputedStyle(firstFoo);
const firstFooColor = gs.getPropertyValue('color');

So with thing like this if I do a console.log(firstFooColor), if the first element is just a .foo I will get rgb(0, 128, 0), and if the second element have the class .inverted the color will be rgb(250, 128, 114).

My question is: is there a way to get var(--color_2, var(--color_1, white)) instead of the color output just by selectionning an element?

Everything I've tried has failed. And I don't want to use things like document.styleSheets, parse all, found the class and compare with the classes of the element, and return the value. If a more complex selector it will be horrible and if there is some @media or other it will be pratically impossible...

Thanks in advance for your help!

1

There are 1 best solutions below

1
On

Here's an attempt to achieve this, and it seems to work (with some conditions): https://codepen.io/zvona/pen/yLjyEbX?editors=0111

For instance, I noticed if you define hex values for colors in CSS, then it doesn't recognise them. So feel free to extend this solution with hexToRbg kind of functions.

Also this is also probably the not most performant solution. Plus I noticed later you had requirements to include also secondary variables.

But what the heck, I'll leave the initial solution here for you to get started with and to improve it, whenever needed.

And here's the actual code:

const getUncomputedValue = (elem, target) => {
  const element = document.querySelector(elem);

  if (!element) {
    return;
  }

  const styleValue = getComputedStyle(element).getPropertyValue(target);
  
  if (!styleValue) {
    return;
  }
  
  const allStyling = Array.from(element.computedStyleMap()).filter(([prop, val]) => prop.includes('--') && val[0].toString().includes(styleValue));
  
  return allStyling.map((style) => `var(${style[0]})`).join(',');
};