2

For example, I have a webpage with such structure in <head>, which is pretty common i guess:

<link rel="stylesheet" href="styles.css"> // here goes big css bundle
<script defer src="main.js"></script> // relatively small javascript bundle with defer attribute

And there is <span id="element"></span> on the page.

CSS bundle contains #element { display: none; }.
JS bundle contains (using jquery here):

$(document).ready(() => {
  console.log($('#element').css('display'));
});

The result will be different from time to time. Sometimes JS executes earlier than CSS and the result is 'inline', sometimes JS executes later and the result is 'none' as I want it to be.

I want my JS bundle to be non-blocking so I use deffered attribute. I am not able to simply put my JS bundle in the end of a page because I use turbolinks and it doesn't allow me to do it.

window:load is not a best option too, because it will be fired when not only css but all resources will be downloaded including images.

So I want JS to be not-blocking and be executed after CSS to get consistent and predictable results. Maybe there is something I can do?

2 Answers 2

1

One option is to add a load event handler for the link element which will then insert the script into the head. Since the script is dynamically added, it will automatically be async. Therefore, it would be non-blocking and executed after the CSS is loaded.

<link id="stylesheet" rel="stylesheet" href="styles.css">

<script>
  var link = document.getElementById('stylesheet');

  link.addEventListener('load', function () {
    var script = document.createElement('script');
    script.src = 'main.js';
    document.head.appendChild(script);
  });
</script>

However, this could cause you a problem. If the stylesheet is cached, then it might not emit a load event (because it's already loaded). For cases like that, you could try checking for link.sheet.cssRules.

Load events on <link> elements seem to historically be a troublesome issue, so I don't know how well this will work.

Here is a CodePen demonstrating the JS loading with a check for link.sheet.cssRules. It currently works for me in Chrome, FireFox, and Edge.

Sign up to request clarification or add additional context in comments.

2 Comments

I've slightly modified your code and tested it in Chrome 64, Safari 11, Firefox 57 and the load event works nice. I guess there will be no problems with modern browsers, which is enough for me. Thank you very much, Andrew.
It turned out that this solution works badly with turbolinks, which I am using. And I accidentally found another solution: stackoverflow.com/questions/48967081/…
1

I found another solution. You can just add a script without src attribute to the <head> with some code, an empty comment for example: <script>//</script>
And that's it. Now all the scripts, even deferred, will wait for styles to apply.
I'm not sure how it works, but I think deferred scripts are queued after a script without src which by standard must wait for css to apply.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.