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.