Skip to content

critical.css (above the fold) optimizations#

A very important technique to improve the perceived initial load performance of a website is to inline the CSS that is used for the first thing the visitors see, the so-called "above the fold" content.

With a CMS like Plone and its Volto frontend, it is difficult to decide, at "build time" what exactly represents that optimal "above the fold" CSS. This CSS could come from various addons installed, it depends on the blocks activated on the frontpage, etc. So this CSS is something that's very specific to every deployed website and, if maximum performance is desired, the critical CSS could be specific to each page in a CMS.

Fortunately there are ways to automate extracting the critical CSS. One such tool is provided from the Plone critical-css-cli repository which can generate a critical.css file from a live website. This tool uses internally critical and a headless Chrome instance to extract the critical css from a running website.

Run it like:

critical-cli -h
critical-cli https://example.com/ -o critical.css

You can pass multiple URLs and screen dimmensions and the extracted CSS will be optimized (duplicate rules will be eliminated, etc). See the Advanced preset of cssnano for details. One last optimization applied strips all @import declarations from the generated CSS.

After that, copy this file to the public/critical.css path (configurable through settings.serverConfig.criticalCssPath). When this file exists, Volto changes the way the CSS files are loaded. By default, the CSS is loaded with two elements in the <head>:

<link rel="preload" href="static/1234.chunk.css" as="style"/>
<link rel="stylesheet" href="1234.chunk.css" />

With critical.css present, the file content is inlined into a <style> tag in the HTML and the <link rel="stylesheet" /> links are moved to the bottom of the generated HTML.

The ideal scenario when dealing with the critical css is to generate it for each possible page, but this complicates the overall architecture: storage, invalidations, async workers, etc have to be taken into account. In case you want to implement this type of scenario, look at Penthouse and override the settings.serverConfig.readCriticalCss function with your own implementation.