loading css with media="none" first
Does it make sense to follow the proposal of adding a media="none" attribute to the link and switch that with "all" once loaded ?
See http://keithclark.co.uk/articles/loading-css-without-blocking-render/
Idea being that whenever the css link element is added some other things might still be going on on the page and those might block once the link element is detected.
That's interesting, I hadn't thought about using media="none" to control the parsing of CSS.
If you want, you can use the before callback to set the media attribute value before the <link> element gets added to the page:
loadjs(['/path/to/foo.js', '/path/to/bar.css'], {
success: function() {},
error: function(pathsNotFound) {},
before: function(path, element) {
/* called for each node before being embedded */
if (path === '/path/to/bar.css') element.setAttribute('media', 'none');
}
});
@amorey great... this should also work for controlling javascript parsing .. will try
EDIT: adding scriptEl.setAttribute('type', 'preload'); on the before callback seems to disable the success callback sadly. This prevents me from preloading js files but only start executing them when certain other criteria are met
it would be nice to have lading css without blocking render support on load, a lot of papers:
https://gist.github.com/scottjehl/87176715419617ae6994
@outaTiME You can use LoadJS to load a CSS file after the window load event fires:
window.addEventListener('load', function() {
loadjs('/path/to/file.css');
});
Yup, im doing in that way but PageSpeed warns the css loading:
<!DOCTYPE html>
<html>
<head>
<script async src="//cdn.rawgit.com/muicss/loadjs/master/dist/loadjs.min.js"></script>
</head>
<body>
<p class="status">Loading...</p>
<script>
var time = Date.now();
window.addEventListener('load', function() {
loadjs('//web.skycop.com.py/skyweb/build/css/skyweb-13cd7264d6.desktop.css', {
success: function() {
console.log('success', Date.now() - time);
document.querySelector('.status').textContent = 'Load success';
},
error: function(pathsNotFound) {
console.error('error', pathsNotFound);
document.querySelector('.status').textContent = 'Load error';
}
});
});
</script>
</body>
</html>
PageSpeed Insights output:

Here my simple example:
http://local.outa.im:8080/desktop/test/non-block-v1.html
@amorey Im trying to understand why async loading in window load event causes a block (as shows in google pagesepeed).
@outaTiME I'm not sure why pagespeed treats it as blocking. Have you tried using the document DOMContentLoaded event instead?
document.addEventListener("DOMContentLoaded", function() {
loadjs('/path/to/file.css');
});
@amorey the DOMContentLoaded event does not guarantee execution after loading of the asynchronous scripts, i tried to do the following and didn't work either:
<!DOCTYPE html>
<html>
<head>
<script async src="//cdn.rawgit.com/muicss/loadjs/master/dist/loadjs.min.js" onload="myInit()"></script>
</head>
<body>
<p class="status">Loading...</p>
<script>
var myInit = function() {
var time = Date.now();
loadjs('//web.skycop.com.py/skyweb/build/css/skyweb-13cd7264d6.desktop.css', {
success: function() {
console.log('success', Date.now() - time);
document.querySelector('.status').textContent = 'Load success';
},
error: function(pathsNotFound) {
console.error('error', pathsNotFound);
document.querySelector('.status').textContent = 'Load error';
}
});
}
</script>
</body>
</html>
Here the new example:
http://local.outa.im:8080/desktop/test/non-block-v2.html
I think that the browser will wait to fire the DOMContentLoaded event until all the scripts in the queue are loaded. This means that in your example, the browser will load loadjs.min.js and skyweb-13cd7264d6.desktop.css before the DOMContentLoaded event fires.
Have you tried loading the CSS file with the rel="preload" attribute?
https://github.com/filamentgroup/loadCSS/blob/master/README.md
You can use the before callback method to set the attribute:
loadjs('//web.skycop.com.py/skyweb/build/css/skyweb-13cd7264d6.desktop.css', {
before: function(path, el) {
el.setAttribute('rel', 'preload');
},
success: function() {
console.log('success', Date.now() - time);
document.querySelector('.status').textContent = 'Load success';
},
error: function(pathsNotFound) {
console.error('error', pathsNotFound);
document.querySelector('.status').textContent = 'Load error';
}
});
hi again @amorey, i dont think so, take a look my first example using the load event, this event fires after DOMContentLoaded, yup preaload rule fix the warning but only for few browsers (https://caniuse.com/#search=preload).
The best efforts using loadCSS was (without pollyfill):
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
its possible to took el reference in success callback? to execute the onload script?
The DOM element doesn't get passed into the success callback but you can attach an id in the before callback and fetch it in the success callback. You can also cache a reference to it in before and use it in success.
@amorey — Have you tried changing the rel attribute to rel="preload" in the before callback?
Because I can't get it to work properly…
The way to do it adds an onload handler, changing the rel back to stylesheet.
Note: support for rel="preload" is assumed. You should feature-detect it (and with no support skip running all this code in before(). To test support I used the simple FilamentGroup check, but you could go further with DOMTokenList support.
The thing is, of course, that stylesheets downloaded with rel="preload" as="style" get downloaded, but not applied to the page. Changing to rel="stylesheet" is required to apply the styles.
Now: I've ran into strange issues adding the onload event handler to the e element:
- It seems both the
preloadand thestylesheet(in my onload) triggeronload: my stylesheet is downloaded multiple times. - Even after changing to
rel="stylesheet"my styles are not applied. The link is right there in the HTML (rel="stylesheet"), but my styles are not applied.
Any thoughts?
@davidhund You can set rel="stylesheet" in the success callback after the CSS file loads:
var linkEl;
loadjs('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css', {
before: function(path, el) {
el.rel = "preload";
el.as = "style";
linkEl = el;
},
success: function() {
linkEl.rel = "stylesheet";
}
});
Here's an example with JSFiddle: https://jsfiddle.net/muicss/9qLjbc9e/
Let me know if that helps!