I'm trying to eliminate 2 CSS files that are render blocking on my site - they appear on Google Page Speed Insights. I have followed different methods, none of which were a success. But, recently, I found a post about Thinking Async and when I applied this code: <script async src="https://third-party.com/resource.js"></script>
it did eliminate the problem.
However, after publishing, the page lost the styling. I'm not too sure as to what is going on because the code works but it's the styling after upload that doesn't work. Would appreciate your help with this. Thanks
This question is related to
html
css
asynchronous
media="print"
and onload
The filament group recently (July 2019) published an article giving their latest recommendation for how to load CSS asynchronously. Even though they are the developers of the popular Javascript library loadCSS, they actually recommend this solution that does not require a Javascript library:
<link
rel="stylesheet"
href="/path/to/my.css"
media="print"
onload="this.media='all'; this.onload = null"
>
Using media="print"
will indicate to the browser not to use this stylesheet on screens, but on print. Browsers actually do download these print stylesheets, but asynchronously, which is what we want. We also want the stylesheet to be used once it is downloaded, and for that we set onload="this.media='all'; this.onload = null"
. (Some browser will call onload
twice, to work around that, we need to set this.onload = null
.) If you want, you can add a <noscript>
fallback for the rare users who don't have Javascript enabled.
The original article is worth a read, as it goes into more detail than I am here. This article on csswizardry.com is also worth a read.
The simple answer (full browser support):
<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'">
The documented answer (with optional preloading and script-disabled fallback):
<!-- Optional, if we want the stylesheet to get preloaded. Note that this line causes stylesheet to get downloaded, but not applied to the page. Use strategically — while preloading will push this resource up the priority list, it may cause more important resources to be pushed down the priority list. This may not be the desired effect for non-critical CSS, depending on other resources your app needs. -->
<link rel="preload" href="style.css" as="style">
<!-- Media type (print) doesn't match the current environment, so browser decides it's not that important and loads the stylesheet asynchronously (without delaying page rendering). On load, we change media type so that the stylesheet gets applied to screens. -->
<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'">
<!-- Fallback that only gets inserted when JavaScript is disabled, in which case we can't load CSS asynchronously. -->
<noscript><link rel="stylesheet" href="style.css"></noscript>
Preloading and async combined:
If you need preloaded and async CSS, this solution simply combines two lines from the documented answer above, making it slightly cleaner. But this won't work in Firefox until they support the preload keyword. And again, as detailed in the documented answer above, preloading may not actually be beneficial.
<link href="style.css" rel="preload" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="style.css"></noscript>
Additional considerations:
Note that, in general, if you're going to load CSS asynchronously, it's generally recommended that you inline critical CSS, since CSS is a render-blocking resource for a reason.
Credit to filament group for their many async CSS solutions.
Please care to update the answer as all of the above fails to impress google pagespeed insights now.
According to Google this is how you should implement async loading of Css
< noscript id="deferred-styles" >
< link rel="stylesheet" type="text/css" href="small.css"/ >
< /noscript >
<script>
var loadDeferredStyles = function() {
var addStylesNode = document.getElementById("deferred-styles");
var replacement = document.createElement("div");
replacement.innerHTML = addStylesNode.textContent;
document.body.appendChild(replacement)
addStylesNode.parentElement.removeChild(addStylesNode);
};
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
if (raf) raf(function() { window.setTimeout(loadDeferredStyles, 0); });
else window.addEventListener('load', loadDeferredStyles);
</script>
The trick to triggering an asynchronous stylesheet download is to use a <link>
element and set an invalid value for the media attribute (I'm using media="none", but any value will do). When a media query evaluates to false, the browser will still download the stylesheet, but it won't wait for the content to be available before rendering the page.
<link rel="stylesheet" href="css.css" media="none">
Once the stylesheet has finished downloading the media attribute must be set to a valid value so the style rules will be applied to the document. The onload event is used to switch the media property to all:
<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'">
This method of loading CSS will deliver useable content to visitors much quicker than the standard approach. Critical CSS can still be served with the usual blocking approach (or you can inline it for ultimate performance) and non-critical styles can be progressively downloaded and applied later in the parsing / rendering process.
This technique uses JavaScript, but you can cater for non-JavaScript browsers by wrapping the equivalent blocking <link>
elements in a <noscript>
element:
<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'"><noscript><link rel="stylesheet" href="css.css"></noscript>
You can see the operation in www.itcha.edu.sv
Source in http://keithclark.co.uk/
Use rel="preload"
to make it download independently, then use onload="this.rel='stylesheet'"
to apply it to the stylesheet (as="style"
is necessary to apply it to stylesheet else the onload
won't work)
<link rel="preload" as="style" type="text/css" href="mystyles.css" onload="this.rel='stylesheet'">
If you have a strict content security policy that doesn't allow @vladimir-salguero's answer, you can use this (please make note of the script nonce
):
<script nonce="(your nonce)" async>
$(document).ready(function() {
$('link[media="none"]').each(function(a, t) {
var n = $(this).attr("data-async"),
i = $(this);
void 0 !== n && !1 !== n && ("true" == n || n) && i.attr("media", "all")
})
});
</script>
Just add the following to your stylesheet reference: media="none" data-async="true"
. Here's an example:
<link rel="stylesheet" href="../path/script.js" media="none" data-async="true" />
Example for jQuery:
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" type="text/css" media="none" data-async="true" crossorigin="anonymous" /><noscript><link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" type="text/css" /></noscript>
I have try to use:
<link rel="preload stylesheet" href="mystyles.css" as="style">
It works fines, but It also raises cumulative layout shift because when we use rel="preload", it just download css , not apply immediate.
Example when the DOM load a list contains ul, li tags, there is an bullets before li tags by default, then CSS applied that I remove these bullets to custom styles for listing. So that, the cumulative layout shift is happening here.
Is there any solution for that?
The function below will create and add to the document all the stylesheets that you wish to load asynchronously. (But, thanks to the Event Listener
, it will only do so after all the window's other resources have loaded.)
See the following:
function loadAsyncStyleSheets() {
var asyncStyleSheets = [
'/stylesheets/async-stylesheet-1.css',
'/stylesheets/async-stylesheet-2.css'
];
for (var i = 0; i < asyncStyleSheets.length; i++) {
var link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', asyncStyleSheets[i]);
document.head.appendChild(link);
}
}
window.addEventListener('load', loadAsyncStyleSheets, false);
If you need to programmatically and asynchronously load a CSS link:
// https://www.filamentgroup.com/lab/load-css-simpler/
function loadCSS(href, position) {
const link = document.createElement('link');
link.media = 'print';
link.rel = 'stylesheet';
link.href = href;
link.onload = () => { link.media = 'all'; };
position.parentNode.insertBefore(link, position);
}
you can try to get it in a lot of ways :
1.Using media="bogus"
and a <link>
at the foot
<head>
<!-- unimportant nonsense -->
<link rel="stylesheet" href="style.css" media="bogus">
</head>
<body>
<!-- other unimportant nonsense, such as content -->
<link rel="stylesheet" href="style.css">
</body>
2.Inserting DOM in the old way
<script type="text/javascript">
(function(){
var bsa = document.createElement('script');
bsa.type = 'text/javascript';
bsa.async = true;
bsa.src = 'https://s3.buysellads.com/ac/bsa.js';
(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(bsa);
})();
</script>
3.if you can try plugins you could try loadCSS
<script>
// include loadCSS here...
function loadCSS( href, before, media ){ ... }
// load a file
loadCSS( "path/to/mystylesheet.css" );
</script>
<link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet'">
Source: Stackoverflow.com