WpW: Critical CSS and LiteSpeed Cache
Welcome to another installment of WordPress Wednesday!
Today’s topic is: Critical CSS and LiteSpeed Cache
Chances are, if you’ve played around with LiteSpeed Cache for WordPress’ optimization features in the past, you may have encountered the dreaded FOUC, or “Flash of Unstyled Content.” This is caused when the browser loads a page’s content before it loads the styles defined for that content. The browser doesn’t know yet how the content should look, and momentarily displays the content without any formatting at all. This behavior is a side-effect of the Load CSS Asynchronously optimization feature. It’s a common problem, but it has a solution, and that is what we’re going to explore today.
What is Critical CSS?
Your web browser needs two things in order to properly display a page:
- HTML, which includes the content, function and structure of the elements on the page
- CSS, which determines how those elements look when they are displayed
In an unoptimized site, all of the CSS that is linked to in the HTML header is loaded before the HTML body. This approach, however, can lead to a lot of waiting. And so site scoring services (like PageSpeed) recommend that you load CSS asynchronously. Essentially, what this does, is to load the content and the styling separately, without making one wait for the other before continuing.
But this can cause a problem. When page content is loaded before the CSS that styles it, you get FOUC. Basically, you see the text and maybe the images, too, but instead of displaying in the format you expect, the site momentarily looks like something straight out of 1994.
So, how can you load CSS asynchronously and avoid the unstyled content? Critical CSS.
Stylesheets can be large and complex, which is why it takes so long to wait for them to load. However, only a fraction of the styles is necessary for displaying above-the-fold content. It’s that fraction which is called “Critical CSS.” We can quickly load the Critical CSS first, and then, when the rest of the CSS and HTML are loaded together asynchronously, the browser already knows how to display the content that is initially visible.
LSCache has three settings that define how Critical CSS is handled in WordPress.
How LSCache Handles Critical CSS
From the WordPress Dashboard, navigate to LiteSpeed Cache > Settings > Optimize. You’ll find the relevant settings about halfway down the page.
Load CSS Asynchronously
This option defaults to
OFF. When it is OFF, web pages load the normal way, where the browser loads the CSS from the HTML header before continuing on to display the content in the HTML body.
When you turn this option
ON, CSS and HTML will be loaded at the same time. The page can load more quickly this way, but it may initially load without formatting, as described above. To avoid that problem, you will want to generate the Critical CSS and load that first. That is what the next setting is for.
Generate Critical CSS
This option defaults to
ON, but it only works if Load CSS Asynchronously is also
ON. When both settings are enabled, the Critical CSS is generated by LiteSpeed’s remote CCSS server, and then sent back to LSCache.
Note that some themes already generate Critical CSS for you. In that case, you can turn this option
Once the Critical CSS has been generated, it will be loaded first, and then the rest of the CSS will be loaded asynchronously with the HTML. The page will no longer load without formatting. Mission accomplished!
There is one small issue, though. When your site has not yet had the Critical CSS generated (or after a Purge All), the first visitor to request a page will need to wait for LSCache’s remote CCSS server to generate the styles. That can take a few seconds that the visitor may not be willing to spend. This leads us to the next setting.
Generate Critical CSS in the Background
You can avoid having visitors wait for the initial calculation of Critical CSS by turning this option
ON. (It is ON by default, but it will not work unless the previous two options are also ON.)
When this setting is enabled, the first visitor to request the page doesn’t have to wait for the Critical CSS to be generated. Instead of waiting for the remote CCSS server to calculate and return the Critical CSS, LSCache instead adds the page to a cron-based queue to be calculated later in the background. In the meantime, the page continues to load asynchronously for the visitor without waiting.
The only drawback to this approach is that the first visitor is likely to get the FOUC. You need to decide which is worse: a quick flash of unformatted content? or having to wait a few seconds for the Critical CSS to be generated before anything on the page loads at all? If it were me, I’d take the FOUC.
A Few More Details
Critical CSS is generated for the different types of pages that may be displayed on your site, but is not generated page-by-page. For example, there is a set of Critical CSS that is applied to all posts, another that is applied to all category archives, and another that is applied to all product pages, etc.
A Purge All command will delete all generated Critical CSS. However, if you purge an individual page, like
example.com/store/earrings/, the Critical CSS that had been generated for product pages will still be immediately available for use the next time the page is requested.
For more on how CCSS and cache interact, and why you might still be seeing FOUC when CCSS is enabled, read this wiki article.
Please note, you may need to whitelist our remote CCSS server:
Disclaimer: The information contained in this post is accurate for LSCWP v2.3.1 [release log]. If you are using a newer version of the plugin, some details may have changed. Please refer to our wiki for the latest!
Have some of your own ideas for future WordPress Wednesday topics? Leave us a comment!
Don’t forget to meet us back here next week for the next installment. In the meantime, here are a few other things you can do:
- Subscribe to the WordPress Wednesday RSS feed
- Download LiteSpeed Cache for WordPress plugin
- Learn more about the plugin on our website