Asynchronous CSS

Back To TOC
Avoid The Render Blocking Effect of Non-Critical CSS Resources

Load low priority CSS resources in the background without impacting page speed with this simple technique for asynchronous CSS loading.

Jump To The Result

What Is Asynchronous Loading?

Asynchronous loading simply means downloading a file in the background without hindering higher priority resources or otherwise impacting the loading process.

This configuration is ideal for CSS that doesn't apply to initially-visible or above-the-fold content elements and can be added to the page later in the loading process. Also called non-critical CSS, loading low priority CSS files this way is an important step to limit render blocking resources and improve website speed.

Terms & Techniques

While the terms lazy loading, on-demand, deferred, and asynchronous are all methods to help avoid render blocking and often used semi-interchangeably, there are some key differences:

  • Lazy Loaded = Loaded preemptively in anticipation of a need.

    For example, as the page is scrolled or when a particular content element is revealed. Lazy loading images is the most common use, but it can also be effective for other resources like CAPTCHA plugins used toward the bottom of the page.

  • On-Demand = Loaded only when needed.

    Similar to lazy loading, but typically in response to a more specific, purposeful action like loading a video when the play button is clicked or loading CAPTCHA resources when a user starts interacting with a form.

  • Deferred - Loaded or applied later in the initial loading process.

    As with a simple way to defer Google Analytics, the defer attribute can be added to external <script> references to both load in the background and execute after initial rendering of the page, right before the <DOMContentLoaded> event.

  • Asynchronous = Loaded or applied independently of other resources.

    Asynchronous loading is a good choice for files that are part of general page loading, but shouldn't interfere with higher priority resources in the loading process.

Reconfiguring CSS For Speed

CSS resources are typically included on a page with a <link> reference to an external file:

HTML
<!-- other <head> stuff -->

<link rel="stylesheet" href="styles.css">

</head>

A conventional, render blocking reference like this to a very small CSS file (<10KB minified & compressed) is desirable for critical styles that apply to the initially-visible or above-the-fold parts of the page so that users don't see a flash of unstyled content. However for non-critical CSS that only applies to below-the-fold content, the render blocking effect negatively impacts page speed.

Learn more about the loading process, critical vs non-critical CSS and how to avoid render blocking resources.

Enter Asynchronous CSS

Rather than interrupting the loading process with a conventional, render blocking CSS reference, asynchronous CSS loads in the background. The HTML can continue to be analyzed by the browser, other more important resources can continue to load and the page can be rendered and appear on screen as quickly as possibly.

Asynchronous CSS uses a simple combination of the media attribute and a bit of JavaScript to pull the old switcheroo:

HTML
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.onload=null;this.removeAttribute('media');">

Jump down for the complete solution.

This technique benefits from the fact that browsers still download file references with non-matching media conditions, but do so in the background at a low priority without blocking page rendering.

Valid HTML

Sometimes the media attribute technique is seen with a value like "none", which isn't valid HTML. (And who needs that?) A value like "print" or even "(max-width:1px)" or similar won't match any user screen conditions while remaining valid code.

No-JavaScript Fallback

Since it relies on JavaScript, a conventional <link> reference wrapped in a <noscript> is an easy fallback:

HTML
<noscript>
    <link rel="stylesheet" href="non-critical.css">
</noscript>

Increase Priority

For otherwise well-optimized pages without many other competing resources, the priority of asynchronously-loaded CSS can be optionally increased by adding a preload resource hint:

HTML
<link rel="preload" href="non-critical.css" as="style">

Note the added as attribute. Learn all about resource hints and which attributes are required and which are optional.

Not So Fast

Why not simplify and combine the asynchronous <link> reference with preload? Unfortunately browser support for the rel="preload" value isn't universal, so this would have to include a JavaScript fallback to make it a viable option.

Media Conditions

Along with separating critical from non-critical CSS, another great strategy to limit render blocking resources is to organize CSS files by media conditions.

Media queries can selectively prioritize critical resources based on conditions like screen size. All files will be downloaded, but with appropriate priority, and only files with matching media conditions will block rendering.

HTML
<link rel="stylesheet" href="critical-general.css">
<link rel="stylesheet" href="critical-large.css" media="(min-width:60em)">

Without JavaScript

The media attribute technique is the best option for most cases, but what if you need to get a similar effect without using JavaScript?

Placing non-critical CSS references at the end of the page, before the closing </body> tag will have a similar effect:

HTML
<!-- other <head> stuff -->

<link rel="stylesheet" href="critical.css">
</head>

<body>
    <!-- page content -->

<link rel="stylesheet" href="non-critical.css">
</body>

Depending on the quantity and complexity of the page content and other resources, the downside of this method is that files may not begin loading as soon as files referenced in the <head> section, increasing the potential for a flash of unstyled content.

All Together

Putting all of these elements together yields a simple and effective method for asynchronous CSS loading and faster page speed:

HTML
<!-- other <head> stuff (including critical CSS) -->

<!-- optionally increase loading priority -->
<link rel="preload" href="non-critical.css" as="style">

<!-- core asynchronous functionality -->
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.onload=null;this.removeAttribute('media');">

<!-- no-JS fallback -->
<noscript>
    <link rel="stylesheet" href="non-critical.css">
</noscript>

</head>

Asynchronous Google Fonts

Along with improving the loading efficiency of general CSS resources, this is a great technique to eliminate the render blocking effect of Google Fonts.

Async Google Fonts