Optimize your site with Critical CSS
· 5 minutes read
Today, for every public site, the force of the war is ranking on google and other search engine. With a good ranking, you can be sure to get visitors, without use other method for this. For example, recently, I have launched an ad site for shelter adoption without advertising it. My goal was to see how many visitors I can get like that with a high score on Lighthouse, an open-source tool supported by Google for measure your site in different criteria.
One of the main problematic, was to improve my website performance at start-up. When you start to have many line of CSS, the size of your stylesheet increase with it. It causes many no user-friendly behavior, mainly the Cumulative Layout Shift and the First Contentful Paint, two metrics you can analyze with Lighthouse. Let’s see how to deal with that, thank to critical CSS.
What is critical CSS ?
Critical CSS is a technique that allows extract CSS of elements displaying before waterline. We inject it directly in the html page, so the stylesheet is directly display with html, without waiting external stylesheets. With this technique, we can load external stylesheets asynchronously and eliminates the render blocking time due to it.
What is critical CSS improve ?
If you have read the beginning of this post, two metrics are impacted by our stylesheet. Let’s see what each metric measure.
Cumulative Layout Shift
Cumulative Layout Shift (CLS) is one of three Core Web Vitals. This metric measure the stability of a webpage, if it runs smoothly and each interactions flow as naturally as possible. Instable webpages can cause frustrating moments to the user, whether it be for SEO or not, a website must propose a good user experience.
What causes ?
According to Google, there are three reasons why it happens:
- A bad size attributes on your images and video elements.
- Inserting content above existing content, except in response to a user interaction.
- Prefer transform animations to animations of properties that trigger layout changes.
What is the link with critical CSS ?
The mainly link with critical CSS is the second point, if a stylesheet is too big or network conditions are poor, the user can see your site without stylesheet during a small lapse of time. Like you can expect, it’s clearly not user-friendly. We can resolve that with implementing the technique of critical CSS. Let’s see what happens with visual. If you look below, for the first example, we measure the cumulative layout shift for SNCF website.
Like you can see, the footer is load before multiple sections, for a few lapse time. Now, imagine if the visitor have a really bad network, he can see footer for a couple of second and try to click on it, but when other part of the site are loaded, the footer going to move and the visitor click on another element. For the second example, we use my blog, I have integrate critical CSS feature, but many of website integrate it now.
In this example, the first content didn’t move, font size are same, only the logo take time to appear, and it didn’t break my navigation when it was not here.
First Contentful Paint
First Contentful Paint (FCP) is one of three Core Web Vitals. This metric measure the time for display content to visitors. This metric take care only about what is before the waterline. If you follow this post since the first word, you can expect that metric has a similar problem with the Cumulative Layout Shift (CLS). The visitor wait parts of external content for display the final result of the website. Let’s see how we can resolve that with critical CSS.
Set-up critical CSS on my website
That depend of where you want to go, but if you look in the open-source community, you can find many libraries for do this job, let’s see a few :
- Critical, the most famous critical CSS generator
- Penthouse, the original critical path CSS generator
- Critters, generate critical CSS without headless browser
Another option, it’s to manage your critical CSS manually, but that can be really painful to manage it, the only advantage is the fact that you can optimize the CSS injection like you want.
In this set-up, because we are lazy, we will use the easiest path for manage your critical CSS. Let’s go do this with the most famous library, Critical.
First, let’s create a simple project with a homepage and a list :
\ src
---\ scss
------\ module
---------\ reset.scss
------\ app.scss
---\ index.html
---\ list.html
\ webpack.config.js
Secondly, configure your module bundler (webpack in your case) for include each stylesheet in the good webpage :
const CriticalCssPlugin = require('critical-css-webpack-plugin')
module.exports = () => {
const critical = []
// We retrieve all html pages from your src folder
fs.readdirSync(path.join(__dirname, 'src')).forEach(file => {
if (/.html$/.test(file)) {
critical.push(new CriticalCssPlugin({
base: path.resolve(__dirname, 'src'),
src: file,
target: path.resolve(__dirname, 'dist', file),
inline: true,
extract: true,
width: 375,
height: 565
}))
}
})
return {
...
plugins: [
...critical,
],
}
}
If you check the result, we include a class list__paragraph in the list page and the library inject the rule of this class into your list page. Same for the CSS Reset but in both page, it includes only needed rules in the scope of the virtual webpage, 375px in 565px in your example.
Now, we can defer your stylesheet if the user have javascript enabled for optimize your loading time :
<link rel="preload" href="css/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="css/main.css"></noscript>
And… that’s all ! 🎉 Pretty simple no ? You can find a working demo on my github, here.