Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async loading CSS stylesheet using requestAnimationFrame

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.

like image 917
Matej Hostak Avatar asked Feb 08 '15 12:02

Matej Hostak


People also ask

How do I load a CSS file asynchronously?

To load CSS Files asynchronously in both Chrome and Firefox, we can use “preload” browser hint and “media='print'” attribute along with onload event feature in a ordered way. you may use the codes below to load CSS Files without render-blocking resources features in Firefox and Chrome.

Why should I use requestAnimationFrame?

To optimize system and browser resources, it is recommended to use requestAnimationFrame , which requests the browser to execute the code during the next repaint cycle. This allows the system to optimize resources and frame-rate to reduce unnecessary reflow/repaint calls.

Is CSS loaded synchronously?

That's because by default, browsers will load external CSS synchronously—halting all page rendering while the CSS is downloaded and parsed—both of which incur potential delays.


1 Answers

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!

like image 108
danjacobs Avatar answered Oct 08 '22 05:10

danjacobs