How to prevent CSS holding up the display of a web page

In order to build a web page, a browser needs to know what it should look like. And to do that, it needs the styles for that page.

This is why CSS files are often said to ‘block’ render start. In other words, the page can’t begin to display until the CSS files have been loaded and parsed.

This makes a lot of sense.

Except that sometimes, you don’t want CSS to block render start.

This is typically because you want to separate out the styles you need for critical, above-the-fold content from the ones you need for the rest of the page or the rest of the site.

For example, you might have inlined critical styles to get above-the-fold content to display as fast as possible. You’re then left with styles that you need for elements further down the page or that don’t come into play until a visitor starts interacting with the site.

There are a few ways to achieve this, each with different pros and cons and browser support.

1: Prefetching

Prefetching is great for loading styles that you don’t need on the current page but you do need for subsequent pages. It’s easy to implement and it shouldn’t interfere with how the current page’s resources load.

<link rel="prefetch" href="style.css">

 

Prefetch is now very well supported, the only notable exception being iOS.

2: Reference CSS immediately above the content that needs it

This is the ‘progressive rendering CSS’ suggested by Jake Archibald. The idea is that CSS should only block the display of content to which it applies.

In theory, it sounds like it should be a good way to prevent a CSS file from blocking render start.

And in some browsers, it is.

In Internet Explorer and iOS Safari, progressive CSS works.

In the following test in Internet Explorer (run in Performance Analyser), the CSS file was referenced just above the only image on the page. It was also loaded with a 10 second delay. 

The page started to render in just under a second, but content after the CSS file was only displayed after the CSS had loaded. The filmstrip shows how this would have looked to the end user.

How progressive CSS works in Internet Explorer

It’s a bit different in Firefox, where CSS referenced in the document body doesn’t block the display of any content.

We thought Chrome was going to follow Internet Explorer, and we wrote about this a couple of years ago. However, it seems that nothing has changed and that even a style sheet at the bottom of the page can still block render start.

The filmstrip below shows how our test page loaded and displayed in Chrome.

Filmstrip showing a script-injected style sheet blocking render start in Chrome

One thing that is changing is what constitutes valid HTML, with style sheet references outside of the document head valid in the latest versions of HTML5.

3: Using a script to inject CSS

You can add a CSS reference to a page with a few lines of JavaScript:

 var link = document.createElement('link'); 
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', 'style.css');
document.head.appendChild(link);

 

This makes the CSS file non-blocking in most browsers, Chrome included this time (something else we’ve written about before). In iOS, however, render start is blocked until the CSS has finished loading.

4: Using loadCSS

Filament Group’s loadCSS is a very lightweight piece of JavaScript for loading CSS files in a non-blocking way. It relies on preloading the file, then switching the rel attribute from preload to stylesheet as soon as it’s loaded, so that the style sheet can be applied. The script includes a polyfill as a workaround for browsers that don’t support this.

Although this is a very neat solution, it’s still more code than any of the alternatives. However, it does work across browsers, so if browser support is particularly important to you, this is the one to go for – at least until the various browsers start behaving in the same way.

The one caveat for all of the above, of course, is that it's a good idea to test what works for you once you've thrown your other scripts and style sheets into the mix. 

Summary

Forconvenience, here’s a brief round-up of how different browsers deal with the techniques outlined in this post. 

 

Chrome

Internet Explorer

Firefox

iOS Safari

Prefetch

Doesn’t block render start

Doesn’t block render start

Doesn’t block render start

Not supported

Progressive CSS

Blocks render start

Works – only content that follows the CSS is blocked

Doesn’t block the display of any content

Works – only content that follows the CSS is blocked

Script-injected CSS

Doesn’t block render start

Doesn’t block render start

Doesn’t block render start

Blocks render start

loadCSS

Doesn’t block render start

Doesn’t block render start

Doesn’t block render start

Doesn’t block render start

 

You might also be interested in:

What are the benefits and drawbacks of loading JavaScript asynchronously?

 

Published date:  16 November 2017

Written by:  Alex Painter

comments powered by Disqus

Filter By Service

Filter By Date