/blog/articles/

Load CSS asynchronously with loadCSS

The problem with CSS is that we can't load it asynchronous natively. In contrast to the script tag there is no async attribute for the link tag.

<link rel="stylesheet" href="dist/css/style.min.css">
<script src="dist/js/picturefill.min.js" async></script>

You might think why on earth do I want to load CSS asynchronously, this would complete mess up the rendering of the site. You are right. But what if you want to load your webfonts CSS so you don't block rendering only because of some custom fonts like I described in my latest article. Or what if you load the critical CSS which is needed to display the above the fold content synchronously and then load the rest of the pages CSS async so it doesn't block rendering and your site is usable faster. There is no native way to doing that. You coudl put the CSS at the end of your page but this would still not make it load async, it just would get loaded later in the process.

In my last post about FOUT and loading web fonts asynchronously I mentioned loadCSS by the Filament Group, or rather Scott Jehl. Scott created a little Javascript function which allows us to load CSS asynchronously. I have used it in several projects and it works perfectly. It's really easy to use: First you place the loadCSS function in the head of your site. Make sure to always grab the newest version from GitHub in case there was an update.

<script>
    /*!
    loadCSS: load a CSS file asynchronously.
    [c]2014 @scottjehl, Filament Group, Inc.
    Licensed MIT
    */
    function loadCSS( href, before, media ){
        "use strict";
        var ss = window.document.createElement( "link" );
        var ref = before || window.document.getElementsByTagName( "script" )[ 0 ];
        var sheets = window.document.styleSheets;
        ss.rel = "stylesheet";
        ss.href = href;
        ss.media = "only x";
        ref.parentNode.insertBefore( ss, ref );
        function toggleMedia(){
            var defined;
            for( var i = 0; i < sheets.length; i++ ){
                if( sheets[ i ].href && sheets[ i ].href.indexOf( href ) > -1 ){
                    defined = true;
                }
            }
            if( defined ){
                ss.media = media || "all";
            }
            else {
                setTimeout( toggleMedia );
            }
        }
        toggleMedia();
        return ss;
    }
</script>

Then you can pass the a stylesheet url into the function:

<script>
    loadCSS( "dist/css/non-critical-style.min.css" );
</script>

It's a good idea to also put a link tag into a noscript tag so users without Javascript still get the CSS.

<noscript><link rel="stylesheet" href="dist/css/non-critical-style.min.css"</noscript>

There are also two optional arguments to the loadCSS function:

before and media. By default loadCSS inserts your stylesheet link tag before the first script tag in the DOM. If you don't want that and like to decide where the link tag gets inserted, you can define the element before which the tag should be placed with the before argument:

loadCSS( "dist/css/non-critical-style.min.css", window.document.getElementsByTagName( 'script' )[ 1 ] );

This would insert the stylesheet before the second

<script> tag instead of the first. With the media argument you can set the media attribute of the stylesheet. Default is media="all":

loadCSS( "dist/css/non-critical-style.min.css", "", "print" );

That's it. Happy CSS async loading thanks to Scott Jehl!

Martin Wolf

Hi, I’m Martin Wolf, a Freelance Frontend Web Developer from Germany.
I believe in hard work and sharing what I know.

Contact me

Interested in working with me? Fantastic! The best way to get in touch is by email (hello@martinwolf.org). I’m looking forward to hearing from you.