Asynchronous CSS

Page Speed Checklist

Eliminate The Render Blocking Effect Of Low-Priority CSS

Load low priority, non-critical 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 or async loading refers to downloading and applying a page resource in the background, independently of other resources and without otherwise impacting the initial 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 asynchronously is a common technique to eliminate render blocking CSS and improve website speed.

Terms & Techniques

The terms lazy loading, on-demand, deferred, and asynchronous are all related to the various methods for minimizing initial-load page weight and eliminating render blocking resources. Although 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 deferring 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

External CSS resources are included on the page with a <link> reference to the 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 appropriate 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.

Optimize the loading process with a progressive approach.

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 once the file is loaded:

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

(This is the core functionality of asynchronous CSS - jump down for the complete solution.)

Breaking It Down

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.

(this.onload=null; avoids calling onload again in some browsers.)

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.

Increase Loading Priority

For otherwise well-optimized pages without many other competing resources, the loading priority of asynchronously-loaded CSS can also be optionally increased by adding a fetchpriority="high" attribute:

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

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>

Media Conditions

Along with separating critical from non-critical CSS, another beneficial strategy to eliminate render blocking CSS 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 has 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 like critical CSS -->

<!-- core asynchronous functionality (optionally increase loading priority with fetchpriority="high" ) -->
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.onload=null;this.removeAttribute('media');" fetchpriority="high">

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

</head>

Async CSS For Google Fonts

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

Optimize Google Fonts