![Milica Mihajlija](https://web.dev/images/authors/mihajlija.jpg) Milica Mihajlija [X](https://twitter.com/bibydigital) [GitHub](https://github.com/mihajlija) [Homepage](https://mihajlija.github.io/)

<br />

> [!IMPORTANT]
> **Important:** This codelab describes an advanced performance technique that can improve performance, but can also lead to bugs if not implemented properly. **Most sites should be able to achieve all of our recommended performance targets without implementing this technique.**

> [!IMPORTANT]
> To follow this codelab, open [this Glitch](https://glitch.com/edit/#!/critical-css-starter) in a second tab.

> [!NOTE]
> **Note:** This codelab uses Chrome DevTools. [Download Chrome](https://www.google.com/chrome) if you don't already have it.

Whether you use a UI library or handcraft your styles, shipping a significant amount of CSS delays rendering because the browser must download and parse CSS files before it can show the page.

This responsive ice cream gallery is built with [Bootstrap](https://getbootstrap.com/). UI libraries like Bootstrap speed up development, but that often comes at the expense of bloated and unnecessary CSS, which can slow down your load times. Bootstrap 4 is 187 KB, while [Semantic UI](https://semantic-ui.com/), another UI library, is a whopping 730 KB uncompressed. Even when minified and gzipped, Bootstrap still weighs around 20 KB, well over the [14 KB threshold](https://web.dev/articles/extract-critical-css) for the first roundtrip.

[Critical](https://github.com/addyosmani/critical) is a tool that extracts, minifies and inlines [above-the-fold](https://web.dev/articles/extract-critical-css) CSS. This allows above-the-fold content to be rendered as soon as possible, even if CSS for other parts of the page has not yet loaded. In this codelab, you'll learn how to use Critical's npm module.

## Measure

- To preview the site, press **View App** . Then press **Fullscreen** ![fullscreen](https://web.dev/static/images/glitch/fullscreen.svg).

To run a Lighthouse audit on this site:

1. Press \`Control+Shift+J\` (or \`Command+Option+J\` on Mac) to open DevTools.
2. Click the **Lighthouse** tab.
3. Click **Mobile**.
4. Select the **Performance** checkbox.
5. Clear the rest of the checkboxes in the Audits section.
6. Click **Simulated Fast 3G, 4x CPU Slowdown**.
7. Select the **Clear Storage** checkbox. With this option selected, Lighthouse will not load resources from the cache, which simulates how first-time visitors would experience the page.
8. Click **Run Audits**.

![Audits panel of Chrome DevTools, powered by Lighthouse](https://web.dev/static/articles/codelab-extract-and-inline-critical-css/image/audits-panel-chrome-devt-1a8ccbed41384.png)

When you run an audit on your machine, the exact results may vary, but in the filmstrip view, you'll notice the app has a blank screen for quite a while before finally rendering the content. This is why [First Contentful Paint (FCP)](https://web.dev/articles/fcp) is high and why overall performance score is not great.

![Lighthouse audit showing performance score of 84, FCP 3 seconds and a filmstrip view of loading the app](https://web.dev/static/articles/codelab-extract-and-inline-critical-css/image/lighthouse-audit-showing-74cf2e516cb25.png)

Lighthouse is here to help you fix performance issues, so look for solutions in the **Opportunities** section. **Eliminate render-blocking resources** is listed as an opportunity and that's where Critical shines!

![Lighthouse audit 'Opportunities' section listing 'Eliminate render-blocking resources'](https://web.dev/static/articles/codelab-extract-and-inline-critical-css/image/lighthouse-audit-opportu-b1d16b00344ff.png)

## Optimize

- Click **Remix to Edit** to make the project editable.

To speed things up, Critical is already installed and an empty configuration file is included in the codelab.

In the configuration file `critical.js`, add a reference to Critical and then invoke the `critical.generate()` function. This function accepts an object containing the configuration.

    const critical = require('critical');

    critical.generate({
        // configuration
    },(err, output) => {
      if (err) {
        console.error(err);
      } else if (output) {
        console.log('Generated critical CSS');
      }
    });

Error handling isn't mandatory, but it's an easy way to gauge the operation success in the console.

### Configure Critical

The table below contains some useful Critical options. You can check out all of the [available options on GitHub](https://github.com/addyosmani/critical#usage).

| Option | Type | Explanation |
|---|---|---|
| `base` | string | The base directory for your files. |
| `src` | string | HTML source file. |
| `dest` | string | The target for the output file. If CSS is inlined the output file is HTML. If not, the output is a CSS file. |
| `width`, `height` | numbers | Viewport width and height in pixels. |
| `dimensions` | array | Contains objects with width and height properties. These objects represent the viewports you want to target with above-the-fold CSS. If you have media queries in your CSS, this allows you to generate critical CSS that covers multiple viewport sizes. |
| `inline` | boolean | When set to true, the generated critical CSS is inlined in the of the HTML source file. |
| `minify` | boolean | When set to true, Critical minifies the generated critical CSS. Can be omitted when extracting critical CSS for multiple resolutions because Critical automatically minifies it to avoid duplicate rule inclusion. |

Below is a configuration example for extracting critical CSS for multiple resolutions. Add it to `critical.js` or play around and tweak the options.

    critical.generate({
      base: 'public/',
      src: './index.html',
      dest: './index.html',
      inline: true,
      dimensions: [
        {
          height: 500,
          width: 300,
        },
        {
          height: 720,
          width: 1280,
        },
      ]
    }, (err, output) => {
      if (err) {
        console.error(err);
      } else if (output) {
        console.log('Generated critical CSS');
      }
    });

In this example, `index.html` is both the source file and the destination file because the `inline` option is set to true. Critical first reads the HTML source file, extracts critical CSS and then overwrites `index.html` with critical CSS inlined in the `<head>`.

`dimensions` array has two viewport sizes specified: 300 x 500 for extra small screens and 1280 x 720 for standard laptop screens.

`minify` option is omitted because Critical automatically minifies the extracted CSS when there are multiple viewport sizes specified.

### Run Critical

Add Critical to your scripts in `package.json`:

    scripts: {
      "start": "node server.js",
      "critical": "node critical.js"
    }

1. Click **Terminal** (note: if the Terminal button does not show you may need to use the Fullscreen option).

To generate critical CSS, in the console, run:

    npm run critical
    refresh

![Success message saying 'Generated critical CSS' in the console](https://web.dev/static/articles/codelab-extract-and-inline-critical-css/image/success-message-saying-g-e2359b437448f.png) Success message in the console

> [!NOTE]
> **Note:** Glitch console and editor don't automatically sync, so `refresh` command is neccessary to update the editor with files generated from the console.

Now in the `<head>` tag of `index.html`, generated critical CSS is inlined between `<style>` tags, followed by a script that loads the rest of the CSS asynchronously.
![index.html with inlined critical CSS](https://web.dev/static/articles/codelab-extract-and-inline-critical-css/image/indexhtml-inlined-criti-9c5e8661497d1.png) Inlined critical CSS

## Measure again

Follow the steps from the beginning of the codelab to run Lighthouse performance audit again. The results you get will look similar to this:

![Lighthouse audit showing performance score of 100, FCP 0.9 seconds and improved filmstrip view of loading the app](https://web.dev/static/articles/codelab-extract-and-inline-critical-css/image/lighthouse-audit-showing-32baf18653d47.png)

> [!TIP]
> **Success:** The filmstrip view shows that content is rendered much sooner and this is reflected in improved paint metrics. And "Eliminate render-blocking resources" has been eliminated! 🎉