Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getComputedStyle: wait for external style sheets?

Say you have an external stylesheet (<link>), followed by a <script>. Is the external stylesheet always applied before the <script> executes, so that getComputedStyle always respects the external stylesheet's rules?

Or are browsers allowed to run JavaScript before earlier stylesheets have been applied?

Example:

<!doctype html>
<html>
  <head>
    <link href="/my-stylesheet.css" rel="stylesheet" />
  </head>
  <body>
    <div id="foo"></div>
    <script>
      window.getComputedStyle(document.getElementById('foo')).width
      // => "200px" due to stylesheet - is this reliable?
    </script>
  </body>
</html>
like image 736
Jo Liss Avatar asked Apr 17 '15 22:04

Jo Liss


People also ask

What is getcomputedstyle?

Definition and Usage. The getComputedStyle() method gets all the actual (computed) CSS property and values of the specified element. The computed style is the style actually used in displaying the element, after "stylings" from multiple sources have been applied. Style sources can include: internal style sheets, external style sheets,...

How can I make sure that an external stylesheet has loaded?

Would be easier. If you want make sure that an external stylesheet has loaded, then you can use the window load event which will fire when page resources such as external stylesheets and images have finished loading and the page also will have its final layout:

What is a Computed Style?

The computed style is the style actually used in displaying the element, after "stylings" from multiple sources have been applied. Style sources can include: internal style sheets, external style sheets, inherited styles and browser default styles.

Should I use inline or embedded stylesheets?

However, if the styles need to be applied across multiple documents, you should link to an external style sheet instead of using individual embedded style sheets. Using embedded stylesheets holds a distinct advantage over inline styles which only allow you to address one HTML element at a time.


2 Answers

In short: YES this is reliable.

To prove I created following testserver based on nodejs:

Directory:

/testserver.js
/server/index.js
/server/style.js

testserver.js creates a node js server and ensures, that each request takes two seconds to load:

var express = require('express');
var app = express();
app.listen(8888);
app.use(function(req,res,next){
    setTimeout(next, 2000);
});
app.use(express.static('./server'));

My index.html:

<html>
<head>
    <link href="style.css" rel="stylesheet" />
</head>
<body>
    <div id="mydiv"></div>
<script>
console.log(window.getComputedStyle(document.getElementById('mydiv')).width);
</script>
</body>
</html>

My style.css

#mydiv {
    position: absolute;
    background: #ff0000;
    height: 10px;
    width: 100px;
}

Now I test it by starting my server and calling http://localhost:8888/index.html

In the Chrome developer tools the timeline looks like this: Timeline

As you can see the index.html file loads before style.css

And the Javascript Console outputs 100px as expected: Console

Because of the fact, that there are no errors in js-console and the only output is the expected 100px I proved that the adoption in question is true.

EDIT: Now I tested more: This works on Chrome with 2s, 5s and 60s => Works! Furthermore I tested it on Firefox, Opera and Safari with 2s. => Works!

Sorry I've got no IE available.

EDIT 2: I just did more research:

The behaviour I figured out is defined by W3C. A loading style file is blocking script execution when it was defined by link-tag or style-tag:

A style sheet in the context of the Document of an HTML parser or XML parser is said to be a style sheet that is blocking scripts if the element was created by that Document's parser, and the element is either a style element or a link element that was an external resource link that contributes to the styling processing model when the element was created by the parser, and the element's style sheet was enabled when the element was created by the parser, and the element's style sheet ready flag is not yet set, and, the last time the event loop reached step 1, the element was in that Document, and the user agent hasn't given up on that particular style sheet yet. A user agent may give up on a style sheet at any time.

Note: Giving up on a style sheet before the style sheet loads, if the style sheet eventually does still load, means that the script might end up operating with incorrect information. For example, if a style sheet sets the color of an element to green, but a script that inspects the resulting style is executed before the sheet is loaded, the script will find that the element is black (or whatever the default color is), and might thus make poor choices (e.g. deciding to use black as the color elsewhere on the page, instead of green). Implementors have to balance the likelihood of a script using incorrect information with the performance impact of doing nothing while waiting for a slow network request to finish.

W3C Blocking Scripts

And as defined in this document, in the parsing process the script will not execute until the blocking style has been loaded.

like image 114
Dustin Hoffner Avatar answered Sep 27 '22 17:09

Dustin Hoffner


If you want make sure that an external stylesheet has loaded, then you can use the window load event which will fire when page resources such as external stylesheets and images have finished loading and the page also will have its final layout:

window.addEventListener('load', function() {
    window.getComputedStyle(document.getElementById('foo')).width
});

You can also devise a test to see if the stylesheet has already been loaded by putting a specific and unique style rule in the stylesheet that applies to a specific DOM element (which could even be hidden) and then you can get that style with getComputedStyle() and see if it matches what it should be. If so, then the stylesheet has been loaded. If not, then the stylesheet has not yet been loaded. But, if you still need to wait until it's loaded, the the window load event is what you would want to use.

like image 36
jfriend00 Avatar answered Sep 27 '22 16:09

jfriend00