Menu Search
Jump to the content X X
Smashing Conf New York

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

Understanding Critical CSS

The web is slow, yet there are a few simple strategies to make websites faster. One of them is inlining critical CSS into the <head> of your pages, yet how exactly do you do it if your site contains hundreds of pages, or even worse, hundreds of different templates? You can’t do it manually. Dean Hume explains an easy way to get it done. If you’re a seasoned web developer, you might find the article obvious and self-explanatory, but it’s a good piece to show to your clients and junior developers for sure. — Ed.

Delivering a fast, smooth web experience is an important part of building websites today. Most of the time, we develop websites without understanding what the browser is actually doing under the hood. How exactly does the browser render our web pages from the HTML, CSS and JavaScript that we create? How can we use this knowledge to speed up the rendering of our web pages?

If I’m looking to quickly improve the performance of a website, Google’s PageSpeed Insights1 tool is the first place I go. It can be very helpful when trying to profile a web page and find areas for improvement. You simply enter the URL of the page that you want to test, and the tool provides you with a list of performance suggestions.

If you’ve ever run one of your own websites through the PageSpeed Insights tool, you may have come across the following suggestion.

Google PageSpeed Insights2
CSS and JavaScript will block the rendering of your page. (View large version3)

I must admit, the first time I saw this, I was a little confused. The suggestion reads:

“None of the above-the-fold content on your page could be rendered without waiting for the following resources to load. Try to defer or asynchronously load blocking resources, or inline the critical portions of those resources directly in the HTML.”

Fortunately, the solution to this problem is simpler than it seems! The answer lies in the way that the CSS and JavaScript are loaded in your web page.

What Is Critical CSS? Link

A request for a CSS file can significantly increase the time it takes a web page to render. The reason is that by default the browser will delay page rendering until it has finished loading, parsing and executing all the CSS files referenced in the <head> of your page. It does this because it needs to calculate the layout of the page.

Unfortunately, this means that if we have a really large CSS file and it takes a while to download, our users will end up waiting until the whole file has been downloaded before the browser can begin rendering the page. Fortunately, there is a sneaky technique that allows us to optimize the delivery of our CSS and mitigate the blocking. This technique is known as optimizing the critical rendering path.4

The critical rendering path represents the steps that the browser takes to render a page. We want to find the minimum set of blocking CSS, or the critical CSS, that we need to make the page appear to the user. A critical resource is any resource that may block the initial rendering of the page. The idea behind this is that the website should get the first screen’s worth of content (or “above-the-fold” content) to the user in the first few TCP packets of response. To give you a brief idea of how this would work for a web page, take a look at the image below.

Understanding what is critical5
Critical CSS is the minimum set of blocking CSS required to render the first screen’s worth of content to the user. (View large version6)

In the example above, the critical part of the web page is only what the user can see when they first load the page. This means that we only need to load the minimum amount of CSS required to render the top portion of the page across all breakpoints. For the remainder of the CSS, we don’t need to worry as we can load it asynchronously.

How do we determine what is considered critical CSS? Determining the critical CSS for a page is rather complex and requires you to walk through the web page’s DOM. Next, we need to determine the list of styles that currently apply to each element in view. Doing this manually would be a tedious process, but there are a number of great tools that will do this automatically.

In this article I am going to show you how to improve your web page rendering speed using critical CSS, and show you a tool that will help you do this automatically.

Critical CSS In Action Link

To start working with the critical CSS for our web page, we need to change our approach to the way we handle the CSS – this means splitting it into two files. For the first file, we extract only the minimum set of CSS required to render the above-the-fold content, and then we inline it in the web page. For the second file, or the non-critical CSS, we asynchronously load it so as not to block the web page.

It might seem a bit weird at first, but by inlining the critical CSS into our HTML, we can eliminate the additional round-trips in the critical path. This allows us to deliver the critical CSS in one round-trip and present something to users as soon as possible.

In order to understand what this might look like represented as HTML, the code below gives a basic example.

<!doctype html>
<head>
  <style> /* inlined critical CSS */ </style>
  <script> loadCSS('non-critical.css'); </script>
</head>
<body>
  ...body goes here
</body>
</html>

In the code above, we are extracting the critical CSS and inlining it in the HTML between the style tags. Next, we are using the loadCSS(); function to asynchronously load the remaining, non-critical CSS. This is important because we are essentially off-loading the bulkier (non-critical) CSS and injecting it into the web page in the background.

At first, this may seem like a nightmare to maintain. Why would you manually want to inline a snippet of CSS in every page? There is good news, though – the process can be automated and in this example, I am going to run through a tool called Critical7. Originally created by Addy Osmani8, it is a Node.js package that allows you to automatically extract and inline critical-path CSS in HTML pages.

We are going to combine this with Grunt9, the JavaScript task runner, to automatically process the CSS. If you have never used Grunt before, the website has some very detailed documentation10, as well as a variety of tips for configuring your project. I have also previously blogged11 about this awesome tool.

Getting Started Link

Let’s begin by firing up the Node.js console and navigating to the path of your website. Install the Grunt command line interface by typing the following command into your console:

npm install -g grunt-cli

This will put the grunt command in your system path, allowing it to be run from any directory. Next, install the Grunt task runner with the following command:

npm install grunt --save-dev

Then install the grunt-critical12 plugin.

npm install grunt-critical --save-dev

Next, you need to create a Gruntfile that contains the task configuration for your project. Mine looks a little like the code below.

module.exports = function (grunt) {

grunt.initConfig({
  critical: {
    dist: {
      options: {
        base: './'
      },
      // The source file
      src: 'page.html',
      // The destination file
      dest: 'result.html'
      }
    }
  });

  // Load the plugins
  grunt.loadNpmTasks('grunt-critical');

  // Default tasks.
  grunt.registerTask('default', ['critical']);
};

In the code above, I configured the Critical plugin to look at my page.html file. It will then process the CSS against the given page and calculate the critical CSS. Next, it will inline the critical CSS and update the HTML page accordingly.

Run the plugin by typing grunt into the console.

Running Grunt Critical CSS13
Automating web performance using Grunt. (View large version14)

If you navigate to the folder, you should now notice a file called result.html that contains the inlined critical CSS and the remaining CSS loaded asynchronously. Your web page is now ready to rock and roll!

Behind the scenes, this plugin actually uses PhantomJS15, a headless WebKit browser, to capture the required critical CSS. This means it is able to silently load your web page and test for the optimal critical CSS. This functionality also gives the plugin flexibility when it comes to different screen sizes. For example, you can provide different screen dimensions and the plugin will capture and inline your critical CSS accordingly.

critical: {
  dist: {
    options: {
      base: './',
      dimensions: [{
        width: 1300,
        height: 900
      },
      {
        width: 500,
        height: 900
      }]
    },
    files: [
      {src: ['index.html'], dest: 'dist/index.html'}
    ]
  }
}

The code above will process the given file against multiple dimensions and inline the appropriate critical CSS. This means that you can run your site against a number of screen widths and ensure that your users will still have the same experience throughout. As we know, mobile connections using 3G and 4G can be flaky at the best of times – that’s why this technique is so important to mobile users.

Using Critical In A Production Environment Link

Using a tool like Critical is a great way to automatically extract and inline your critical CSS without having to change the way you develop your websites, but how does this fit into the real world? To put the newly updated files into action, you simply deploy as you normally would – nothing needs to change on your production environment. You need only remember that you will need to run Grunt every time you build or make changes to your CSS files.

The code samples we have run through in this article have covered the use of a single file, but what happens when you need to process the critical CSS for multiple files, or even an entire folder? Your Gruntfile can be updated to handle multiple files, similar to the example below.

critical: {
  dist: {
    options: {
      base: './',
      dimensions: [{
        width: 1300,
        height: 900
       },
       {
        width: 500,
        height: 900
      }]
    },
    files: [
      {src: ['index.html'], dest: 'dist/index.html'},
      {src: ['blog.html'], dest: 'dist/blog.html'}
      {src: ['about.html'], dest: 'dist/about.html'}
      {src: ['contact.html'], dest: 'dist/contact.html'}
    ]
  }
}

You could also run the task against every HTML file in a given folder using the code below:

critical: {
  dist: {
    options: {
      base: './',
      dimensions: [{
        width: 1300,
        height: 900
      },
      {
        width: 500,
        height: 900
      }],
      src: '*.html',
      dest:  'dist/'
    }
  }
}

The code samples above provide an insight into how this could be achieved across your website.

Testing Link

As always, testing any new changes is very important. If you’d like to test your changes, there are some amazing tools that are freely available online. Head over to Google’s PageSpeed Insights16 and run your URL through the tool. You should notice that your web page now no longer has any blocking resources and your performance improvements suggestion has gone green – woohoo! And you are probably familiar with another great tool, WebPagetest17, too.

Using WebPagetest is a great way to test that your web page renders in a timely manner.18
Using WebPagetest is a great way to test that your web page renders in a timely manner. (View large version19)

It is a free tool that allows you to run a website speed test from multiple locations around the globe. Apart from an informative analytical review of your web page, if you choose “Visual Comparison20”, the tool will compare two web pages with each other. This is a great way to compare your results before and after updating your critical CSS and play back the differences.

The idea behind using critical CSS is that our web pages render sooner, thus presenting something to users as soon as possible. The best way to measure this is to use the speed index21. It is a measurement, taken by WebPagetest, that measures how quickly the page contents are visually populated. The SpeedIndex measures the visual progress of the visible page loading and computes an overall score for how quickly the content was painted. Try to compare22 your SpeedIndex measurement before and after you have made changes by inlining your critical CSS. You will be impressed at how much of a difference it can make to your render times.

Diving A Little Deeper Link

As with most optimization techniques, there are always pros and cons that might affect your site. One of the downsides with inlining your critical CSS is that you miss out on caching CSS in the browser because it has been inlined in the page. If we are dealing with dynamic pages that change often, we wouldn’t want to cache the HTML pages themselves. This means that the CSS inlined in the HTML is redownloaded every time23. There is a lot to be said for inlining only the critical CSS and instead asynchronously loading the remaining non-critical CSS. We can always cache this non-critical CSS. Depending on which side of the fence you sit with this, there are a lot of arguments for and against the concept of inling your CSS in the <head>, but for more information I recommend reading “A counter statement: Putting the CSS in the head24” by Hans Christian Reinl.

If you use a content delivery network (CDN), it is also worth remembering that you should still serve your non-critical CSS from the CDN. Doing so allows you to serve cached resources directly from the edge, delivering much faster response times, instead of routing all the way to the origin server to get them.

For traditional web pages, the technique of inlining your CSS works well, but it might not always be applicable depending on your situation. What if you have client-side JavaScript that generates HTML? What if you work on a single page application? If you can output as much of the critical CSS as soon as possible, it will boost page rendering, too. It’s important to understand how critical CSS works and if it applies to you. I like Guy Podjarny’s stance on this:

“Despite all these limitations, Inlining is still a good and important tool in the world of Front-End Optimization. As such, you should use it, but be careful not to abuse it.”
—Guy Podjarny

In “Why Inlining Everything Is NOT The Answer25”, he provides good recommendations as to when you should and shouldn’t inline your CSS.

It’s Not Perfect Link

While many of the tools required to generate and inline critical CSS are constantly improving, there might be a few areas for improvement. If you notice any bugs in your project, open up an issue26 or pull request and help contribute to the project on GitHub.

Optimizing the critical rendering path for your website can go a long way towards improving your page load times. Using this technique allows us to use a responsive layout without compromising on its well-known benefits. It’s also a great way to ensure that your page loads quickly without holding back on your design.

Further Resources Link

If you prefer to use another build system such as Gulp, you can use the plugin directly without downloading Grunt. There is also a useful tutorial showing how to optimize a basic page with Gulp27.

There are other plugins that will extract your critical CSS, such as Penthouse28, and criticalCSS29 from the Filament Group. I also thoroughly recommend reading “How we make RWD sites load fast as heck30” by the Filament Group for a good overview of how they use this technique to ensure that their web pages load as quickly as possible.

The editor-in-chief of Smashing Magazine, Vitaly Friedman, wrote an article about how Smashing Magazine improved the performance31 of this website using this technique. If you would like to learn more about the critical rendering path, there is a useful course available for free on the Udacity website32. The Google Developers website33 also has some good content that covers optimizing CSS delivery34. Patrick Hamman also wrote a great piece on how to identify critical CSS35 in his workshop, Building a Faster Web.

Are you inlining critical CSS in your project by default? What tools are you using? What problems have you been running into? Share your experiences in the comments to this article!

(il, rb, ml, og)

Footnotes Link

  1. 1 https://developers.google.com/speed/pagespeed/insights/
  2. 2 https://www.smashingmagazine.com/wp-content/uploads/2015/08/01-blocking-CSS-opt.jpg
  3. 3 https://www.smashingmagazine.com/wp-content/uploads/2015/08/01-blocking-CSS-opt.jpg
  4. 4 https://developers.google.com/web/fundamentals/performance/critical-rendering-path/optimizing-critical-rendering-path?hl=en
  5. 5 https://www.smashingmagazine.com/wp-content/uploads/2015/08/02-browser-opt.jpg
  6. 6 https://www.smashingmagazine.com/wp-content/uploads/2015/08/02-browser-opt.jpg
  7. 7 https://github.com/addyosmani/critical
  8. 8 http://addyosmani.com/blog/
  9. 9 http://gruntjs.com/
  10. 10 http://gruntjs.com/getting-started
  11. 11 http://deanhume.com/Home/BlogPost/automatically-removing-unused-css-using-grunt/6101
  12. 12 https://github.com/bezoerb/grunt-critical
  13. 13 https://www.smashingmagazine.com/wp-content/uploads/2015/08/03-Critical-CSS-grunt.gif
  14. 14 https://www.smashingmagazine.com/wp-content/uploads/2015/08/03-Critical-CSS-grunt.gif
  15. 15 http://phantomjs.org/
  16. 16 https://developers.google.com/speed/pagespeed/insights/
  17. 17 http://www.webpagetest.org/
  18. 18 https://www.smashingmagazine.com/wp-content/uploads/2015/08/04-webpagetest-filmstrip-opt.jpg
  19. 19 https://www.smashingmagazine.com/wp-content/uploads/2015/08/04-webpagetest-filmstrip-opt.jpg
  20. 20 http://www.webpagetest.org/video/
  21. 21 https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index
  22. 22 http://www.webpagetest.org/video/
  23. 23 http://calendar.perfplanet.com/2011/why-inlining-everything-is-not-the-answer/
  24. 24 https://medium.com/@drublic/a-counter-statement-putting-the-css-in-the-head-f98103d09ce1
  25. 25 http://calendar.perfplanet.com/2011/why-inlining-everything-is-not-the-answer/
  26. 26 https://github.com/addyosmani/critical/issues
  27. 27 https://github.com/addyosmani/critical-path-css-demo#tutorial
  28. 28 https://github.com/pocketjoso/penthouse
  29. 29 https://github.com/filamentgroup/criticalCSS
  30. 30 http://www.filamentgroup.com/lab/performance-rwd.html
  31. 31 https://www.smashingmagazine.com/2014/09/08/improving-smashing-magazine-performance-case-study/
  32. 32 https://www.udacity.com/course/ud884
  33. 33 https://developers.google.com/web/fundamentals/performance/critical-rendering-path/
  34. 34 https://developers.google.com/web/fundamentals/performance/critical-rendering-path/optimizing-critical-rendering-path?hl=en
  35. 35 http://patrickhamann.com/workshops/performance/tasks/2_Critical_Path/2_2.html
SmashingConf New York

Hold on, Tiger! Thank you for reading the article. Did you know that we also publish printed books and run friendly conferences – crafted for pros like you? Like SmashingConf Barcelona, on October 25–26, with smart design patterns and front-end techniques.

↑ Back to top Tweet itShare on Facebook

Dean Hume is a software developer, Google Developer Expert and author of the book Fast ASP.Net Websites. An avid blogger and contributor to various tech and coding websites, he brings a strong desire to constantly build his skillset and help do the same for those around him by writing, presenting, or training on various subjects.

  1. 1

    Techniques like this may be OK for HTTP/1.1, but they’re antipatterns in HTTP/2. I really wish we’d stop suggesting things like this *at all* and instead shift to using HTTP/2 and pushing the appropriate resources to the client.

    HTTP/2 support is becoming quite wide, and it’s wider still if you use SPDY too (http://caniuse.com/#feat=http2,spdy).

    The time has come for HTTP/2-first web development. Can we *please* stop recommending these sorts of techniques and help people to shift to effective HTTP/2 arrangements instead?

    33
    • 2

      You can also use a good old technic : early flushing. Send the cookies and a minimal header as soon as possible. The header should at least reference your CSS/JS files so the browser can request them (or parse the JS and the CSS if they are in the browser cache) while the full page is not ready yet.
      You can also include your html header so the preloader can find its images and download them. Also, use Ressource Hints (https://w3c.github.io/resource-hints/) to make the browser resolve domains, preconnect to other domains, or even fetch ressources.
      HTTP2 push is promising but more complex to implement. The minimal header I’m talking about can be managed entirely by the frontend people.

      Also, I don’t use a CDN because in a SPDY/HTTP2 world, it can be worst. It was for me.
      https://thethemefoundry.com/blog/why-we-dont-use-a-cdn-spdy-ssl/
      Even with HTTP, you shouldn’t use one (or worst, multiple) CDN most of the time. I mean : having to resolve hosts for google font, jquery CDN etc. is a terrible idea. Once the browser starts parsing your page, it means that it already resolved your domain and opened a connexion (plus expanded the TCP congestion window, eventually).
      That means that your first asset will be downloaded almost immediately so make sure that it’s the biggest one.

      One more thing : if you really want to use domain sharding (AVOID it with HTTP2), you might want to use your server IP -if possible- instead of a subdomain for technical assets (i.e. : that won’t be indexed by search engines). That way, the browser still sees two domains and can open twice more connexions, but you avoid one DNS resolution.

      3
      • 3

        To clarify : I’m not the author of the post on thethemefoundry.com. I quoted this link as a reference.

        0
    • 4

      Frederik Krautwald

      August 13, 2015 4:09 pm

      Really? Guess if you don’t care about iPhone/iPad/Android users, then you could probably scoop the HTTP/2-first approach.

      -2
      • 5

        Reuben Molinares

        August 13, 2015 6:47 pm

        Don’t Safari and Chrome for iOS, as well as Chrome for Android support HTTP/2 already?

        1
    • 6

      +1!

      0
    • 7

      Chris – I agree with you. This technique will definitely become an anti pattern in HTTP2 and you are correct in stating that HTTP2 support is becoming wide amongst browsers. However, the reality right now is that many servers don’t support (or haven’t rolled out) HTTP2 just yet. So while the browsers support it, the servers just aren’t serving content using HTTP2 just yet.

      It’s going to take time for for HTTP2 to become widespread, but using techniques like this, we can immediately pass on these benefits to our users. Using tools like Grunt make it easy enough for us to add/remove this functionality when the time comes to move our servers to HTTP2. Let’s make the web faster for our users right now!

      9
  2. 8

    How would you run this on a dynamic platform, eg. wordpress or drupal?

    7
  3. 15

    To make a small suggestion: I would add the noscript-Tag in your 1st code example (with a short explanation).

    But besides that nice article!

    2
  4. 16

    Very interesting concept. I do have to +1 for those that mentioned that we are getting close to the HTTP2 standard which will help issues like these significantly. But, none the less, pairing this with HTTP2… well, now were talking about shaving seconds of load time. At scale, a very valuable effort.

    0
  5. 17

    But what about cache? Of course, page loading would be faster with inline styling … for a one page website. But you’re forcing larger (follow-up) pages to people, some of who don’t have that much bandwidth.
    Also, follow-up pages would be slower as it contains “extra” inline styling and the browser has no cache of it.
    Is it really a good idea?

    1
    • 18

      Maybe some lines of JS to store the inline code in localStorage? Haven’t tried it yet, but sounds reasonable to me.

      0
  6. 19

    If the size of the css file is making you performance troubles, I have a feeling that you probably have a problem with not writing the best css you could.
    The principle is useful if you are using a lot of vendor scripts. Prioritizing and making some of them inline would help in that situation.
    But really, what kind of improvement would it bring for the majority of the web? (We are also talking only first load, before everything is cached)

    2
  7. 20

    I don’t think this good way to go. You can always use caching, cdn, minify css and it will be probably will better solutions. Based on your screenshot you only gained 0.1s

    3
  8. 22

    Jonas Ohlsson

    August 15, 2015 7:47 am

    Great article, glad someone’s talking about performance here!

    A few things that could have been pointed out in article: :)

    • People who don’t want to use Node etc can use the online version:
    http://jonassebastianohlsson.com/criticalpathcssgenerator

    • Critical uses Penthouse for generating critical css (so issues/suggestions regarding the generated css should go to Penthouse)

    • (I should double check what critical does in this case to be sure, but:) If write mobile first css, the
    generated critical css for a smaller viewport will always be a subset of critical css for larger viewport, hence you only need the larger one, unless you use server side detection.

    • Why not talk about explicit gains of using critical css? On 3G connections you would see improvements on Time to first paint of at least 3s on an average site. Perhaps the screenshot from WPT could have been from such a case. :)

    Just some feedback, I care about these things (I wrote Penthouse).

    Cheers, thanks again for article!

    2
  9. 23

    Does it have to be exclusive? Can’t critical parts be inlined and then appear again in the non-critical ressource? It would allow for different inline content while still maintaining a complete CSS file. How would browsers handle redundant definitions introduced by such an approach?

    0
    • 24

      Karsten Buckstegge

      August 19, 2015 8:45 am

      What you have to keep in mind is that the critical CSS only displays a small portion of your website, everything else is provided by the other file. Therefore it is still majorly important to keep that file as small and performant as possible, to make sure that the user (especially on slow mobile connections) will not only have a fast initial experience but will also have well behaving content after he starts scrolling.

      By putting the critical CSS into the external CSS file again you create a bigger and slower file and that is bad practice.

      0
  10. 25

    Excellent tutorial. Would like to reiterate the same question as Josh and Scott – could this work for WordPress?

    0
  11. 26

    Stephen Johnston

    August 16, 2015 2:46 am

    One thing I have wondered. Can the critical CSS parts be repeated in your main CSS? I know this has some theoretical performance impact, but it is likely tiny. Can you do it this way?

    0
  12. 27

    Jonas Ohlsson

    August 16, 2015 11:25 am

    Regarding question of repeating critical css in general css:

    In the majority of cases you want to repeat it, so your general css stays complete and can be re-used on the subsequent page views (as it gets cached). There are a few cases where this might not apply (f.e. if you have an app with only one server side rendered page), but in general this is what you want to do.

    Regarding using with WordPress:
    I recommend generating your critical css with Penthouse (or criticalCSS from the Filament Group), then just inlining it in a php ~ header file, something like:

    Here’s a GitHub Gist of how I use it on my own site:
    https://gist.github.com/pocketjoso/58cb89ad9e69e4da297e

    1
    • 28

      Thanks. It is easy to extract the critical css – was looking to see how to extract the non-critical. Glad to see I can duplicate the critical in the non-critical.

      0
  13. 29

    Awesome article, very helpful

    1
  14. 30

    We had a play with this technique as well (using uncss) and eventually decided against it. The main reason is that when you load most of your CSS async, no longer can your JS assume the CSS is actually applied before that JS runs.

    Thus if you have JS that affects styling/layout on the page, it may now base those calculations on wrong values, since the CSS isn’t applied yet.

    1
  15. 31

    I thought the CSS between the “head” tags are called “Internal” and the ones inside the single HTML element tags are called “Inline”!

    6
  16. 32

    Speed up your website by adding a block of non-cacheable code in the head of every single page of if.
    WTF are you smoking, dude ?

    6
  17. 33

    Mentions nothing about … which is surprising.

    0
  18. 34

    Mentions nothing about style scoped…

    0
  19. 35

    Mark Simchock

    August 21, 2015 3:24 am

    @Dean – How about a follow up article – as routine at it might be – on how to use this technique proactively during the design phase? Sure this trick / hack can be slapped on after the fact, but perhaps that could be a bit more graceful if design thought ahead and gave some consideration to dev?

    Or as I like to say:

    Design without consideration for “manufacturing” isn’t design. It’s art.

    :)

    0
  20. 36

    Hey Dean,
    nice article – I’m under the impression that any inline Javascript calls are HTML parser blocking – so your call to critical CSS should probably be made at the end of the document body rather than in the head, AFAIK inline javascript can never be called asynchronously.

    0

↑ Back to top