0

I am attempting to get the value of a CSS variable in my JavaScript code. I am using the following code snippet to achieve this. In this case I am getting a certain shade of red I defined in my CSS.

let red = getComputedStyle(document.documentElement).getPropertyValue('--red')

The issue is that this code only works when I wrap it in a setTimeout block shown below,

setTimeout(() => {
  let red = getComputedStyle(document.documentElement).getPropertyValue('--red')
}, 10)

So the JavaScript seems like it needs to wait for a moment for the CSS to finish loading. Is there a way to get the value of CSS variables without having to wait an explicit amount of time like I have shown above?

Also I discovered that I do not need the setTimout when I run my app through the VS Code Live Server extension but I do need to use when I open the HTML file through my File Explorer.

Michael
  • 101
  • 4
  • 1
    Does this answer your question? [Is $(document).ready() also CSS ready?](https://stackoverflow.com/questions/1324568/is-document-ready-also-css-ready) – jmargolisvt Aug 29 '21 at 14:10

2 Answers2

1

If I had to guess, the reason that setTimeout() is working here is that it's giving time for your stylesheets to load. In other words, without setTimeout you're trying to access this CSS variable before the DOM - and more importantly, your stylesheet(s) - are fully loaded. Try executing your code in a 'load' callback:

window.addEventListener('load', () => {
  let red = getComputedStyle(document.documentElement).getPropertyValue('--red');
}

This way, your Javascript code will only execute when your stylesheets are loaded.

Brendan Bond
  • 1,737
  • 1
  • 10
  • 8
1

So the JavaScript seems like it needs to wait for a moment for the CSS to finish loading.

That's probably the time for the CSS file to be fetched across the network. You can detect when that happens using the load event on the link element that specifies the CSS, guarding against hte possibility it's already fired:

const link = document.querySelector(/*...selector for the link element loading the stylesheet...*/);
if (link.sheet && link.sheet.cssRules && link.sheet.cssRules.length) {
    // It's already loaded, get the variable
} else {
    link.addEventListener("load", function() {
        // It's loaded now, get the variable
    });
}

Note that the code assumes the stylesheet has at least one rule.

You probably want to apply some timeout or an error handler for situations where the sheet doesn't load for some reason.

That if can be more concise in modern JavaScript using the optional chaining operator:

if (link.sheet?.cssRules?.length) {
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875