Implementing Critical CSS on your website
Tags: css, criticalcss, frontend, webperf
Published: 2020-02-15 23:34:00

---
title: Implementing Critical CSS on your website
published: true
date: 2017-02-28 21:34:00 UTC
tags: css,critical-css,frontend,webperf
canonical_url: https://nystudio107.com/blog/implementing-critical-css
---

# Implementing Critical CSS on your website

### Imple­ment­ing Crit­i­cal CSS is an essen­tial part of mod­ern web­site devel­op­ment, this arti­cle shows you how to do it

Andrew Welch / [nystudio107](https://nystudio107.com)

![Critical Css Stopwatch](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/critical-css-stopwatch.jpg)

When I men­tion Crit­i­cal CSS to many fron­tend devel­op­ers, I’m often met with a coun­te­nance that’s a sub­tle mix­ture of con­fu­sion and skep­ti­cism. ​“_Oh, you’re one of those guys,”_ they think. _Fringe._

But Crit­i­cal CSS isn’t an eso­teric prac­tice reserved only for neck­beards; it’s a essen­tial part of mod­ern web devel­op­ment. There is quite a bit of con­fu­sion over what it is, and what it does, so let’s demys­ti­fy it.

<aside>
                                Our goal is sim­ply to get the web­page to ren­der as quick­ly as we can for our user. Crit­i­cal <span>CSS</span> is an impor­tant tool to help us reach that goal.
                            </aside>

Crit­i­cal CSS is about _cour­tesy_ and _respect_ for the vis­i­tors of our web­site. They have tak­en the bold step of vis­it­ing our web­site — some­thing mar­ket­ing-types spend tons of time and mon­ey to make hap­pen — we owe it to them to reas­sure them that they’ve made a good deci­sion, and to be respect­ful of their time.

This means we don’t make them wait. Peo­ple _hate_ to wait. As the [A Pret­ty Web­site Isn’t Enough](https://dev.to/gaijinity/a-pretty-website-isn-8217-t-enough-1nbj-temp-slug-3932740) arti­cle dis­cuss­es in detail, they may be vis­it­ing our web­site from all man­ner of devices and cir­cum­stances where patience is not an option.

Crit­i­cal CSS is one facet of build­ing a per­for­mant web­site to make our users hap­py, and to make our Search Engine Results Page (SERP) hap­py. I won’t go into the SEO ben­e­fits here, but if you’ve inter­est­ed, you can read more about it in the [Mod­ern SEO: Snake Oil vs. Sub­stance](https://dev.to/gaijinity/modern-seo-snake-oil-vs-substance-4l5k-temp-slug-8632935) article.

![Happy People](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/happy-people.jpg)

That’s our goal. Now let’s see how to do it.

## So what exact­ly is Crit­i­cal CSS, Anyway?

Crit­i­cal CSS is sim­ply a method of extract­ing _only_ the CSS that is need­ed to ren­der the ​“above the fold” con­tent on a web­site, and then _inlin­ing that CSS_ on our web­page. By doing so, we ensure that the brows­er can ren­der the page imme­di­ate­ly for the user vis­it­ing it.

The phrase ​“above the fold” comes from this thing we used to make out of dead trees called a ​“news­pa­per.” Any­thing that was ​“above the fold” on a news­pa­per is what is imme­di­ate­ly seen by some­one glanc­ing at the front page of a fold­ed newspaper.

![Newspaper Above The Fold](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_992x558_crop_center-center_82_line/newspaper-above-the-fold.jpg)

So we’ve appro­pri­at­ed this phrase for our mod­ern ​“Inter­net of things” world to mean the con­tent that is vis­i­ble to a user on their device with­out any scrolling. We want it to load quick­ly, so we use Crit­i­cal CSS.

There’s no wait­ing around for a mon­strous <kbd>600K</kbd> frame­work-based CSS to load, there’s no mas­sive ren­der tree that the brows­er has to con­struct, there’s no extra <kbd>http</kbd> request need­ed to load the CSS. It’s all right there.

Then while the user is read­ing our web­page, hap­pi­ly sip­ping their cof­fee, we load the full site CSS _asyn­chro­nous­ly_, which caches it on their device.

<aside>
                                This con­tributes enor­mous­ly to per­ceived per­for­mance, a key met­ric of vis­i­tor satisfaction
                            </aside>

Before you cast stones at the heretic, yes, we are _inlin­ing CSS._ This is not an inher­ent­ly bad thing; indeed, the smart folks over at Google have made it a [manda­to­ry part of the Google AMP stan­dard](https://dev.to/gaijinity/google-amp-should-you-care-3din-temp-slug-933989).

But we’re doing it smart­ly. The Crit­i­cal CSS is inlined when they first vis­it our web­site. _First impres­sions are incred­i­bly impor­tant, after all._ After that, since we know they’ve down­loaded and cached our full site CSS, we just set a cook­ie so we don’t need to both­er inlin­ing CSS anymore.

This makes it fast. Our goal with build­ing a per­for­mant web­site is to elim­i­nate bot­tle­necks so that the brows­er can ren­der our page as quick­ly as pos­si­ble, and our vis­i­tors can smile.

Even if images and oth­er web­page ele­ments are still load­ing, at the _very least_, peo­ple will be able to read the text on the web­site. Any­thing beats star­ing at a blank white screen.

Besides, we opti­mized our image load­ing as per the [Cre­at­ing Opti­mized Images in Craft CMS](https://dev.to/gaijinity/creating-optimized-images-in-craft-cms-2hc5-temp-slug-2354251) right?

On a typ­i­cal web­page, the non-<kbd>gzip</kbd> ​’d size of the Crit­i­cal CSS usu­al­ly ranges between <kbd>10k</kbd> to <kbd>30k</kbd>, depend­ing on how crazy the design­er has gone with CSS selec­tors. So it’s not bad at all, and pos­i­tive­ly minus­cule com­pared to the images and oth­er con­tent a typ­i­cal web­page loads.

![Bottleneck](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_576x205_crop_center-center_100_line/bottleneck.jpg)

You may have run [Google Page­Speed Insights](https://developers.google.com/speed/pagespeed/insights/) on a web­site, and won­dered why it was com­plain­ing about **Elim­i­nate ren­der-block­ing JavaScript and CSS in above-the-fold con­tent**. That’s what we use Crit­i­cal CSS for.

The CSS part, any­way, for the block­ing JavaScript you’ll need to use an async JavaScript loader as described in the [Load­JS as a Light­weight JavaScript Loader](https://dev.to/gaijinity/loadjs-as-a-lightweight-javascript-loader-3c1k-temp-slug-8245779) & [Using Sys­temJS as a JavaScript Loader](https://dev.to/gaijinity/using-systemjs-as-a-javascript-loader-54ff-temp-slug-340380) articles.

Lest you think that <kbd>http2</kbd> will solve this prob­lem for you, it will not. While <kbd>http2</kbd> does sup­port the serv­er-push of crit­i­cal resources, not all web servers sup­port it yet, and not all web browsers sup­port it yet either.

Even when they do, you still have only _one_ pipe you’re attempt­ing to push these resources down, so we still don’t want to shove our full CSS down the pipe before our web­site can load. We _still_ need a way to extract just the CSS that is need­ed to ren­der the ​“above the fold” con­tent, even with <kbd>http2</kbd>.

What we’re doing here is essen­tial­ly the [PRPL Pat­tern](https://developers.google.com/web/fundamentals/performance/prpl-pattern/), which is a super-impor­tant pat­tern to use when design­ing mod­ern websites:

- **Push** crit­i­cal resources for the ini­tial URL route.
- **Ren­der** ini­tial route.
- **Pre-cache** remain­ing routes (see [Ser­vice­Work­ers and Offline Brows­ing](https://dev.to/gaijinity/serviceworkers-and-offline-browsing-2gi2-temp-slug-4847358)).
- **Lazy-load** and cre­ate remain­ing routes on demand.

If this all sounds some­what men­tal, it real­ly isn’t that hard to do. This web­site you’re read­ing now uses it, to good effect:

![Pagespeed Insights](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_768x700_crop_center-center_100_line/pagespeed_insights.png)

You will need to be using a fron­tend work­flow automa­tion tool of some sort; whether that means [grunt](http://gruntjs.com/) or [gulp](http://gulpjs.com/) or [npm scripts](https://medium.freecodecamp.com/why-i-left-gulp-and-grunt-for-npm-scripts-3d6853dd22b8#.bfemirh8o) is up to you. You can read more about this in the [Fron­tend Dev Best Prac­tices for 2017](https://dev.to/gaijinity/frontend-dev-best-practices-for-2017-2ol9-temp-slug-5463385) arti­cle if you aren’t using one yet.

Then it’s just a mat­ter of set­ting things up.

## Imple­ment­ing Crit­i­cal CSS with Craft CMS

So enough talk, how do we make this thing hap­pen? The tech­niques out­lined here will show how we imple­ment Crit­i­cal CSS with [Craft CMS](https://craftcms.com/), but the vast major­i­ty of it will apply to any CMS sys­tem or fron­tend dev workflow.

The over­all tech­nique is sim­ple, we gen­er­ate a chunk of Crit­i­cal CSS for each user-fac­ing _tem­plate_. For instance, while there are many blogs on this site, and the con­tent can vary from blog to blog, there is only one <kbd>blog</kbd> template.

Sim­i­lar­ly, we then only need one Crit­i­cal CSS for _all_ of the blog pages, because while the con­tent is dynam­ic and dif­fer­ent, the styles applied to them remain constant.

First, we’ll need to use the fan­tas­tic [crit­i­cal](https://github.com/addyosmani/critical) npm pack­age that lever­ages [pent­house](https://www.npmjs.com/package/penthouse) and [phan­tomjs](https://www.npmjs.com/package/phantomjs) to do the heavy lift­ing. So <kbd>npm install --save-dev critical</kbd> or <kbd>yarn add critical --dev</kbd> and away we go!

![Critical Logo](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_576x270_crop_center-center_100_line/critical-logo.png)

Give <kbd>critical</kbd> a URL, and it ren­ders the actu­al web­page in a _head­less_ brows­er. Then it scrapes the ren­dered web­page look­ing for any CSS that is ren­dered ​“above the fold” and returns it to you.

Pret­ty neat, eh? We just need to do a lit­tle set­up work to send it the right things.

So let’s set up the major tem­plates that we need Crit­i­cal CSS for; I do this in my <kbd>package.json</kbd> file as per the [A Bet­ter package.json for the Fron­tend](https://dev.to/gaijinity/a-better-package-json-for-the-frontend-1gal-temp-slug-5184040) article:

```

"critical": [
        { "url": "", "template": "index" },
        { "url": "blog/stop-using-htaccess-files-no-really", "template": "blog/_entry" },
        { "url": "blog", "template": "blog/index" },
        { "url": "offline", "template": "offline" },
        { "url": "wordpress", "template": "wordpress" },
        { "url": "404", "template": "404" }
    ],

```

So defined in this JSON array, we have just 6 major pages on the web­site. We pro­vide the <kbd>url</kbd> (real­ly it should be called a URI or a path, but what­ev­er) that we append to our <kbd>critical</kbd> url, and we have the <kbd>template</kbd> asso­ci­at­ed with that page.

Again, all of this is shown in all of its glo­ry in the [A Bet­ter package.json for the Fron­tend](https://dev.to/gaijinity/a-better-package-json-for-the-frontend-1gal-temp-slug-5184040) arti­cle, so I won’t repli­cate it here, but we have con­stants for all of these things in our <kbd>package.json</kbd> to keep things DRY.

Next we’ll set up a <kbd>gulp</kbd> task to gen­er­ate our Crit­i­cal CSS. Here’s what mine looks like:

```

//critical css task
gulp.task('criticalcss', ['css'], (callback) => {
    doSynchronousLoop(pkg.globs.critical, processCriticalCSS, () => {
        // all done
        callback();
    });
});

```

The <kbd>['css']</kbd> just ensures that we build our site CSS via the gulp <kbd>css</kbd> task before we run <kbd>criticalcss</kbd>, so that our CSS is always up to date. Typ­i­cal­ly I only run <kbd>gulp criticalcss</kbd> as a final step before deploy­ment, because it can be some­what lengthy, and so we don’t want to rebuild it every time.

The code above may look a lit­tle goofy, why are we call­ing <kbd>doSynchronousLoop()</kbd>? The rea­son is that every gulp task is _asyn­chro­nous_. This means that if you’re gen­er­at­ing a lot of Crit­i­cal CSS, we’re going to spawn a ton of crit­i­cal tasks _all run­ning at the same time_. Which will make your com­put­er cry for mercy.

So instead, we run them one at a time via the handy <kbd>doSynchronousLoop()</kbd> func­tion. It’s not that impor­tant that you under­stand how it works, just what it does. You can alter­nate­ly use the [gulp-run-sequence](https://www.npmjs.com/package/gulp-run-sequence) plu­g­in to achieve the same thing if you like. This will be a non-issue for Gulp 4.0 any­way, when­ev­er it is released.

Here’s what <kbd>doSynchronousLoop()</kbd> looks like; it’s a gener­ic func­tion that you can use any time you need to do some­thing syn­chro­nous­ly in JavaScript:

```

// Process data in an array synchronously, moving onto the n+1 item only after the nth item callback
function doSynchronousLoop(data, processData, done) {
    if (data.length > 0) {
        const loop = (data, i, processData, done) => {
            processData(data[i], i, () => {
                if (++i < data.length) {
                    loop(data, i, processData, done);
                } else {
                    done();
                }
            });
        };
        loop(data, 0, processData, done);
    } else {
        done();
    }
}

```

Don’t wor­ry, it took my brain a bit to fig­ure out how it worked, too. It’s clever.

We pass in the <kbd>data</kbd> that we want processed (our <kbd>pkg.globs.critical</kbd> array), the <kbd>processData</kbd> func­tion that process­es the data (our <kbd>processCriticalCSS()</kbd> func­tion), and the <kbd>done</kbd> call­back func­tion that gets called when the syn­chro­nous loop is done (our anony­mous func­tion that calls <kbd>callback()</kbd> to tell gulp that this task is done).

Final­ly we get to gen­er­at­ing some Crit­i­cal CSS! Here’s what the <kbd>processCriticalCSS()</kbd> func­tion looks like:

```

// Process the critical path CSS one at a time
function processCriticalCSS(element, i, callback) {
    const criticalSrc = pkg.urls.critical + element.url;
    const criticalDest = pkg.paths.templates + element.template + '_critical.min.css';

    $.fancyLog("-> Generating critical CSS: " + $.chalk.cyan(criticalSrc) + " -> " + $.chalk.magenta(criticalDest));
    $.critical.generate({
        src: criticalSrc,
        dest: criticalDest,
        inline: false,
        ignore: [],
        css: [
            pkg.paths.dist.css + pkg.vars.siteCssName,
        ],
        minify: true,
        width: 1200,
        height: 1200
    }, (err, output) => {
        if (err) {
            $.fancyLog($.chalk.magenta(err));
        }
        callback();
    });
}

```

Some of the para­me­ters we’re pass­ing in to crit­i­cal war­rant explanation:

- <kbd>src</kbd> — the URL to the web­page that we want to scrape for Crit­i­cal CSS
- <kbd>dest</kbd> — a file sys­tem path where we want the extract­ed Crit­i­cal CSS saved; I save this right in my <kbd>craft/templates</kbd> direc­to­ry, right along­side the actu­al Twig tem­plate, but with <kbd>_critical.min.css</kbd> append­ed to the file name
- <kbd>ignore</kbd> — we can tell crit­i­cal to ignore cer­tain CSS selec­tors if we want (use­ful for ​“ani­ma­tion done” selec­tors that we don’t want included)
- <kbd>css</kbd> — an array of file sys­tem paths to the CSS we want to use as the ​“dic­tio­nary” of CSS rules it should draw from; you can also omit this, and just have crit­i­cal fig­ure out the CSS you include on the page if you want
- <kbd>width</kbd> & <kbd>height</kbd> — the size of the brows­er you want it to use to ren­der to. I set this to a large square, to be gen­er­ous with the CSS we extract

That’s it! Put all of the pieces togeth­er, and you’ll have Crit­i­cal CSS gen­er­at­ed for each major tem­plate on your web­site. It may not seem like it, but this actu­al­ly scales pret­ty well, and is used on some very large websites.

If you want to delve deep­er into what you can pass into <kbd>critical</kbd>, check out the [crit­i­cal doc­u­men­ta­tion](https://github.com/addyosmani/critical).

So now that we have our CSS, how do we get it into our tem­plates? First, in our <kbd>layout.twig</kbd> we’ll need some­thing like this:

```

{# -- CRITICAL CSS -- #}
    {% set cacheVal = getCookie('critical-css') %}
    {% if not cacheVal or cacheVal != staticAssetsVersion or craft.config.devMode %}
        {{ setCookie('critical-css', staticAssetsVersion, now | date_modify("+7 days").timestamp ) }}
        {% block _inline_css %}
        {% endblock %}
        <link rel="preload" href="{{ baseUrl }}css/site.combined.min.{{staticAssetsVersion}}.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
        <noscript><link rel="stylesheet" href="{{ baseUrl }}css/site.combined.min.{{staticAssetsVersion}}.css"></noscript>
        <script>
            {{ source('_inlinejs/loadCSS.min.js') }}
            {{ source('_inlinejs/cssrelpreload.min.js') }}
        </script>
    {% else %}
        <link rel="stylesheet" href="{{ baseUrl }}css/site.combined.min.{{staticAssetsVersion}}.css">
    {% endif %}

```

This may look hel­la­cious­ly com­pli­cat­ed or at least unfa­mil­iar, but it’s not so bad. Let’s break it down.

First, we use my [Cook­ies](https://github.com/nystudio107/cookies) plu­g­in to get the val­ue of the <kbd>critical-css</kbd> cook­ie (though we could just as eas­i­ly use JavaScript as well). This just stores whether our full site CSS has been down­loaded or not, by stor­ing the _ver­sion_ of the CSS in the cookie.

For my web­sites, I use [serv­er-side file­name-based cache bust­ing](http://nystudio107.com/blog/simple-static-asset-versioning) so that when I change the CSS or JS, I can incre­ment this num­ber, and the cache will be bro­ken for peo­ple vis­it­ing my web­site, and they’ll get the latest.

All you real­ly need to know about this is that <kbd>staticAssetsVersion</kbd> is a num­ber that gets append­ed to a resource, so <kbd>site.combined.min.css</kbd> becomes, say, <kbd>site.combined.min.762.css</kbd>. On the serv­er side of things, it strips this num­ber off, and it loads just the <kbd>site.combined.min.css</kbd> file, but the num­ber did its job and forced the cache to be busted.

You don’t need to use this exact tech­nique to use Crit­i­cal CSS, I’m just explain­ing what it’s doing. We com­pare <kbd>staticAssetsVersion</kbd> to the val­ue stored in the <kbd>critical-css</kbd> cook­ie, and if they don’t match (or the cook­ie does­n’t exist), then we need to inline our Crit­i­cal CSS! It’s done this way, rather than a sim­ple boolean, so that we can ensure our Crit­i­cal CSS is loaded if we’ve changed the CSS on the website.

![Yummy Cookies](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/yummy-cookies.jpg)

Then we store the <kbd>staticAssetsVersion</kbd> in the <kbd>critical-css</kbd> cook­ie, and set it to last for 7 days, so we don’t both­er inlin­ing Crit­i­cal CSS when they’ve already down­loaded the full site CSS. Sev­en days is pret­ty rea­son­able time peri­od to assume that the CSS will stay cached on their device.

Then we declare the block <kbd>`{% block _inline_css %}`</kbd> for our tem­plates that extend our <kbd>layout.twig</kbd> only if Crit­i­cal CSS should be loaded (more on that lat­er), and we use [load­C­SS](https://github.com/filamentgroup/loadCSS) to asyn­chro­nous­ly load our full site CSS using their rec­om­mend­ed <kbd>&lt;link rel=""&gt;</kbd> pattern.

**N.B.:** With [load­C­SS](http://github.com/filamentgroup/loadCSS) as of ver­sion 2.0, we only actu­al­ly _need_ the <kbd>cssrelpreload.js</kbd> JavaScript to han­dle the <kbd>&lt;link rel="preload"&gt;</kbd> pat­tern. The <kbd>loadCSS.js</kbd> script itself is only need­ed if we ever want to call <kbd>loadCSS()</kbd> direct­ly via JavaScript, so you can safe­ly remove <kbd>loadCSS.js</kbd> from your project if you don’t need it.

Remem­ber, all of this hap­pens only if our <kbd>critical-css</kbd> cook­ie tells us we need to load the Crit­i­cal CSS. Once the per­son has loaded the page, we know that the full site CSS has been down­loaded and cached on their device, so we just do a reg­u­lar old <kbd>&lt;link rel="stylesheet"&gt;</kbd> for our site CSS.

Final­ly, we need to give each tem­plate that extends our <kbd>layout.twig</kbd> a chance to feed in the Crit­i­cal CSS it wants to use (it’s unique on a per-tem­plate basis, remem­ber). Here’s what it looks like in my <kbd>blog/_entry.twig</kbd> template:

```

{% block _inline_css %}
    <style>
        {{ source ('blog/_entry_critical.min.css', ignore_missing = true) }}
    </style>
{% endblock %}

```

All this is doing is using the Twig <kbd>source</kbd> func­tion to pull in our min­i­mized Crit­i­cal CSS into the <kbd>`{% block _inline_css %}`</kbd>. And we’re done.

If you want to get real­ly clever about it, you can even do it gener­i­cal­ly, like this:

```

{{ source (_self.getTemplateName() ~ '_critical.min.css', ignore_missing = true) }}

```

If this seems like a whole lot of work, remem­ber that once you have done it once, you can repli­cate it 1,000 times with­out a whole lot of addi­tion­al sweat.

_And it’s worth it_. Make the web a bet­ter place for everyone.

## Tru­ly Dynam­ic Content

If you are doing tru­ly dynam­ic con­tent, such as using a con­tent builder as described in the [Cre­at­ing a Con­tent Builder in Craft CMS](https://dev.to/gaijinity/creating-a-content-builder-in-craft-cms-29ap-temp-slug-2753628) arti­cle, you can still use Crit­i­cal CSS.

Often times peo­ple _think_ they are cre­at­ing dynam­ic con­tent, when they real­ly aren’t, because while the data changes, the CSS rules don’t. Remem­ber, I’m using a con­tent builder for this very blog, but the CSS rules for the above the fold con­tent _do not change_ on a per-blog basis.

But if you tru­ly are doing it in such a way that the above the fold con­tent CSS varies from entry to entry, what you can do is build per-matrix block Crit­i­cal CSS, and then com­bine that to build your Crit­i­cal CSS for each page.

It may sound dif­fi­cult, but it’s not so bad… give it a shot. I may explore it as a future top­ic if peo­ple are interested.

## Further Reading

_If you want to be notified about new articles, follow [nystudio107](https://twitter.com/nystudio107) on Twitter._

<small>Copyright ©2020 nystudio107. Designed by nystudio107</small>