Reputation: 59
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?
Upvotes: 2
Views: 291
Reputation: 59
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.
Upvotes: 1
Reputation: 2786
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.
Upvotes: 1