Matt Bailey
Designer & Developer

Optimising the Critical Rendering Path, and Loading CSS Asynchronously and Conditionally

Go straight to the asynchronous and conditional CSS loading script →

Optimising the Critical Rendering Path

I’ve recently been looking into frontend optimisation, or as clients like to refer to it, “can you fix our slow site?” - in my defence I mainly work with Magento sites, so this is not a straightforward task.

Ilya Gregorik at Google has done some great work educating others in optimising the critical rendering path, and one of his recommendations is to inline critical CSS in the head and defer the loading of other CSS files until after the initial paint.

So can you load CSS at the bottom of the page?

I did some experimenting by loading additional, non-critical CSS files at the bottom of the page. However, this caused a FOUC, a flash of un-styled content (not including things styled by the inlined critical styles in the head of course). I believe this has something to do with <script> tags blocking parallel downloads, i.e. the CSS files have to wait until the Javascript files have downloaded. So they have to go back up in the head…

What was Ilya Gregorik’s advice?

I tweeted Ilya asking his advice and his response led me to the Google Developers page on Optimising CSS Delivery.

It contains an example script that enables you to load a CSS file asynchronously, after the "initial painting of the page. Its styles are applied to the page once it finishes loading, without blocking the initial render of the critical content."

Taking the Google CSS loading script a bit further

This was exactly the kind of thing I was looking for, but I needed to take it a step further. I wanted to be able to detect what page I was on and then load multiple CSS files if necessary - there’s no need to load Product Page styles on the Home Page for example.

Part of the optimisation process I’ve been working on is the modularisation of CSS - creating ‘page type’ or function specific stylesheets rather than lumping everything into one big ‘main.css’. Case in point - I did a test on one of my sites and discovered that 85% percent of the selectors in my `main.css` file were unused on the homepage. While I’m not surprised by this, it bugged me that there was so much redundancy.

Sass and Less have modularisation covered from a preprocessor point of view - if you follow a modular, component based Sass codebase for your projects (which I do) it’s pretty easy to create specific CSS files such as critical.css (which I inline in the head), base.css, category-page.css, product-page.css etc. - but what to do with these new CSS files, especially if the pages are built dynamically on a CMS? How do you load them only when needed?

In a nutshell I modified the script on the Google Developers page, allowing me to pass in page specific classes (in my case the classes the CMS was adding to the body tag), and then filter the loading of CSS files based on that information.

Get your hands on the asynchronous and conditional CSS loading script here →

What about other script loaders?

But can’t you just use an existing script loader for this, something like YepNope? I did think of that and I tried it out. However, I still saw a FOUC. I’m not sure why - maybe it has to do with me having the YepNope tests at the bottom of the page, which slows the down the processing and hence the loading/rendering of the CSS files?

Google’s script (and my modified version) is vanilla Javascript, meaning it doesn’t have any dependencies such as jQuery. It’s inlined in the head, meaning it’s executed right away, and the CSS files are injected in the head so they’re loaded immediately after the first paint but before the rest of the page has rendered.

I’m still in the early stages of using and testing this script, but at first glance it seems to be effective. Let me know if you try it and how you get on?

UPDATE

I was also recently pointed to this CSS loading script by Scot Yehl.

It is very similar to the Google script (and hence, mine), but it doesn’t seem to have the ability to test for Page Type, or to load multiple files - I may be wrong about that though, I haven’t tried it out.