Async loading CSS stylesheet using requestAnimationFrame
Asked Answered
A

3

7

Google recommends (https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery) using following JS code to optimize page speed (async CSS loading)

<script>
  var cb = function() {
    var l = document.createElement('link'); l.rel = 'stylesheet';
    l.href = 'small.css';
    var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h);
  };
  var raf = requestAnimationFrame || mozRequestAnimationFrame ||
      webkitRequestAnimationFrame || msRequestAnimationFrame;
  if (raf) raf(cb);
  else window.addEventListener('load', cb);
</script>

When I use the code above, Page Speed Insights (https://developers.google.com/speed/pagespeed/insights/) recognizes it and gives the page higher score. But the problem is, that this code does not work in older IEs.

For example, IE 8 throws an error "Object requestAnimationFrame is not defined". The problem is obvious, IE 8 does not support RAF, so it throws an error because of undefined object.

I need the website to be functional also in these older IEs, so I decided to update my code as following:

<script>
function loadCss() {
    var l = document.createElement('link');
    l.href = 'http://static.xyz.com/css/style.min.css?v=23';
    l.rel = 'stylesheet';
    l.type = 'text/css';
    l.media = 'screen';
    document.getElementsByTagName('head')[0].appendChild(l);
}

if (typeof requestAnimationFrame === 'function') {
    requestAnimationFrame(loadCss);
}
else if (typeof mozRequestAnimationFrame === 'function') {
    mozRequestAnimationFrame(loadCss);
}
else if (typeof webkitRequestAnimationFrame === 'function') {
    webkitRequestAnimationFrame(loadCss);
}
else if (typeof msRequestAnimationFrame === 'function') {
    msRequestAnimationFrame(loadCss);
}
else if (typeof window.addEventListener === 'function') {
    window.addEventListener('load', loadCss);
}
else {
    window.onload = loadCss;
}

This code is not so pretty, but it works properly in IE7+, Firefox, Chrome etc. But when I test it via Page Speed Insights, it does not recognize that the CSS is loaded asynchronously and does not give me a higher score (it shows an error same as if the CSS was loaded synchronously via ).

My question is: is there an error in my code I am not aware of, or Google simply does not recognize this way of inserting async CSS. It is absolutely important for me, that the code works properly, but I would like to achieve higher score in Page Speed test, as it would be a benefit for SEO purposes.

I am not an expert in Javascript nor layout painting and things like these, but I could not find an explanation of what is going on or where the problem could be.

Thanks in advance for any explanations or hints what to look for.

Aqua answered 8/2, 2015 at 12:48 Comment(7)
Do you absolutely need to load css async?Thyroxine
No, I don't, it is not absolutely necessary. But I would like to be able to load it async as long as it would work and Google would recognize it.Aqua
requestAnimationFrame is supported by all browsers without prefixes so you don't really need mozRequestAnimationFrame, webkitRequestAnimationFrame, and msRequestAnimationFrame. I also feel that for older IE browsers [the only ones that don't support requestAnimationFrame], it might be a better idea to just loadCSS() immediately without waiting for onload. So if (typeof requestAnimationFrame === 'function') { requestAnimationFrame(loadCss); } else { loadCss();}Diffractive
@MatejHostak I have the same problem. Did you find a way around it?Quadruplet
Not yet, but I will post an update if I find a solution.Aqua
Hi Matej, sorry to insist... Did you manage to find a solution? I'm finding the same issue on my website :(.Morea
No, still not, sorryAqua
L
1

This code seemed to do the trick for me (it loads async CSS, Google PageSpeed accepts it and it works on older browsers):

<script>
var cb = function(){
  var styles = ["http://mycdn.co.uk/stylesheet1.css", "http://mycdn.co.uk/stylesheet2.css"];
  for( var i = styles.length - 1; i >= 0; i-- )
  {
    l = document.createElement( 'link' );
    l.rel = 'stylesheet';
    l.href = styles[i];
    h = document.getElementsByTagName( 'head' )[0];
    h.insertBefore( l, h.childNodes[h.childNodes.length-1] );
  };
};

var raf = ( "undefined" != typeof requestAnimationFrame ) ? requestAnimationFrame : false ||
    ( "undefined" != typeof mozRequestAnimationFrame ) ? mozRequestAnimationFrame : false ||
    ( "undefined" != typeof webkitRequestAnimationFrame ) ? webkitRequestAnimationFrame : false ||
    ( "undefined" != typeof msRequestAnimationFrame ) ? msRequestAnimationFrame : false;

if( raf )
{
  raf( cb );
}
else
{
  if( "undefined" != typeof window.addEventListener )
    window.addEventListener( 'load', cb );
  else if( "undefined" != typeof window.attachEvent )
    window.attachEvent( 'onload', cb );
}
</script>

Thanks to Ultrabenosaurus for the code!

Leg answered 19/5, 2016 at 10:41 Comment(0)
H
0

Your code loads css asynchronously, yes. So most likely google just don't recognizes your way. You may try to replace window.onload with attachEvent for ie support maybe that will help

Healion answered 8/2, 2015 at 13:54 Comment(0)
B
0

I faced the same issue, in my case several mobile 'User Experience' issues cause Page Speed Insights analyzed the site before my asynchronously loaded CSS could kick in.

Doing this was a pain, but ended up extracting the basic styling that addressed the UX issues, then placing a minified version of that inline in the header while leaving the bulk of the CSS to be loaded asynchronously through js.

Wish there was a better solution.

Bucci answered 18/4, 2015 at 11:23 Comment(2)
in my case I also have a basic CSS inlined in head and the rest is inserted as described above and there is still this behavior ocurring, so in my case this didn't help, but maybe there's some error elsewhere in my case.Aqua
Matej, do you still get the 'Optimize CSS for delivery' message or something else? Cause your code should have taken care of the CSS delivery issue.Bucci

© 2022 - 2024 — McMap. All rights reserved.