Async CSS

Written by
Published
Updated
Typical Read
2 minutes

The CSS preload/polyfill pattern is something I often see developers do to boost performance. This approach loads any stylesheets as preloads instead, and then use their onload events to change them back to a stylesheet once the browser has them ready. 2 problems with this & most are doing it wrong. Here's the RIGHT way to async CSS.

Asynchronous loading CSS? You’re probably doing it wrong & doing the opposite of what you intend. Learn how to async CSS the right way!

The Quick & Dirty

The RIGHT way to async CSS using the print pattern:

<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">

The WRONG way to aync CSS using the preload pattern:

<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">

Two Problems with the Preload Async CSS Pattern

Unlike script elements, there is no async or defer attribute to simply apply to a link element. To counter this, clever developers came up with the preload pattern — though it does have it’s issues.

  1. It throws network priorities out of whack
  2. It blocks the HTML parser*

* Firefox has a way to avoid #2, but it affects every other browser.

Whatever you apply to it is gonna jump up the line to be downloaded. The use of preload means that these stylesheets, assuming you’re making asynchronous because they aren’t critical, are given a very high priority by browsers — a little bit of the opposite effect. Check out the example below:

Example of what happens when you async CSS
Lines 3-6 are CSS files being loaded asynchronously using the preload pattern. While they aren’t critical to initial render, the use of preload means they arrive before anything else in this case.

Don’t forget about critical CSS

The most effective ways to boost the time to Start Render is to make use of the Critical CSS pattern:

Identify all of the styles needed for Start Render (commonly the styles needed for everything above the fold), inline them in <style> tags in the <head> of your document, and asynchronously load the remaining stylesheet off of the Critical Path.

While this strategy is effective, it’s not simple: highly dynamic sites can be difficult to extract styles from, the process needs to be automated, we have to make assumptions about what above the fold even is, it’s hard to capture edge cases, and tooling still in its relative infancy. If you’re working with a large or legacy codebase, things get even more difficult…

Long story short…

  1. If you’re using the preload/polyfill pattern, switch to the print stylesheet pattern instead.
  2. If there’s external stylesheets that are being loading normally (that is, as a regular stylesheet link), move all inline scripts that you can above it in the markup.
  3. Inline your critical CSS for the fastest possible start render times.

Take a Deeper Dive into Asynchronous CSS

Join the conversation.

Your email address will not be published. Required fields are marked *

All comments posted on 'Async CSS' are held for moderation and only published when on topic and not rude. Get a gold star if you actually read & follow these rules.

You may write comments in Markdown. This is the best way to post any code, inline like `<div>this</div>` or multiline blocks within triple backtick fences (```) with double new lines before and after.

Want to tell me something privately, like pointing out a typo or stuff like that? Contact Me.