Blog

PageSpeed Insights: Removing Render-blocking CSS

If you write javascript which dynamically loads CSS files on your page, you have probably seen PageSpeed Insights complain to you about removing render-blocking CSS. Fixing render-blocking javascript is relatively easy: just add an async attribute to the script, and include it before the closing body tag, or use an async loader like Google Analytics. Fixing render-blocking CSS is a little trickier. We employ a little media query magic to get the job done.

// append css dynamically to head
var head = document.getElementsByTagName('head');
var element = document.createElement('link');
element.rel = 'stylesheet';
element.type = 'text/css';
element.href = '//www.my-external-css.com/my.css';

//here's the magic
element.media = 'non-existant-media';
head.appendChild(element, head.firstChild);
setTimeout(function () {
    element.media = 'all';
});

How it Works

When your browser is creating nodes from a stream of HTML, if it runs across a link tag with rel='stylesheet', it will stop rendering until the stylesheet has loaded (or a long time passes, which results in a horribly ugly FOUC). The browser only stops rendering if the media attribute of the link tag matches the current media. In HTML, a link tag’s media attribute defaults to screen, which will always match when someone is viewing your website.

We take advantage of this feature by initially setting our tag’s media attribute to an impossible to match media (e.g. 'non-existent-media'). That way, when the tag is parsed, the browser does not wait for it to load to continue rendering. When the next tick of javascript executes, we set the media attribute back to a matching media, so that when it loads, we will be able to see it’s effects on the page.

This approach works well for us at AddThis, because the tools we render on user’s websites are secondary in importance to their actual content. While we are loading our CSS, the website is still rendering content that a visitor came there to see. Once the CSS has loaded, we render our tools on the user’s website.

  • kertoon

    Where did you paste the above code?

  • Jake

    The above code is already incorporated into addthis tools. You can use it as a guide if you are writing your own javascript which needs to load CSS files.

  • Should be:

    var head = document.getElementsByTagName(‘head’)[0];

  • Should be:

    var head = document.getElementsByTagName(‘head’)[0];

  • tks.. awesome

  • almamun

    How to load multiple css files with this code?

  • Jake

    Yes, this is correct

  • Jake

    Wrap that code in a function which takes a script path as an argument, and then call it multiple times.

  • revanth001reva

    Doing that is removing the previous css file!

    Is there any script already written?

  • Adnan Siddiqi

    This does not work anymore.

  • Hi Adnan, can you email our support team at help [at] addthis [dot] com with a link to the site you’re working on and information about what CSS you’ve applied this to? Thanks! This will also help with updating this post.

  • Hi Revanth, can you email us at help [at] addthis [dot] com with a link to the site you’re working on? Our support team will be able to assist further.

  • lumia

    can you send me code for render block multiple css please
    imaijoo@gmail.com

  • lumia

    hi did find the solution for multiple if yes kindly send me code thanks imaijoo@gmail.com

  • Hello, can you please reach out directly to our support team at help [at] addthis [dot] com? Thanks!

  • Jumpa

    This was the only method that helped me reach 99/100 on PSI. The only fix I needed was to add [0] in document.getElementsByTagName(‘head’)[0];

  • This doesn’t work anymore :(

  • Tansukh Parmar

    good work