If you want a faster site, one often starts with images. After all, they are the largest asset on the page, and if you can trim those down, that’s a big win. Yet something folks often overlook is the impact of CSS (style sheets) on your site. Not only is optimizing CSS important for how fast your page actually is, but it affects how fast your page feels. Almost every site has external CSS, and that means it usually becomes “render-blocking”. That is, the page cannot be render or display until the CSS files have been downloaded.
Your site might only have one or two CSS files, or it might have a dozen, but they all have to be loaded before the page can be displayed to the end user. That is, unless you optimize the way that your CSS is loaded. Google has recommended various ways to optimize the CSS on your site for years, and we’re going to look at a couple of methods that have been somewhat pitted against each other by a very popular performance plugin. We’ll look at a real world example of both optimization strategies, and discuss the pros and cons of each method.
Low Hanging Fruit
Before we get into the battle, there are some obvious wins that benefit every site. Often, these are already done for you, but it is good to know what they are, just in case.
First of all, your CSS should be minified, which removes excess whitespace to make the CSS file as small as possible. Most plugins and themes will ship with minified CSS and JS, but sometimes unminified CSS slips in, like if you’re using a child theme. Fortunately, pretty much any performance plugin can help you with this, including our own SWIS Performance and the popular Perfmatters plugin. If you look at a CSS file and see a “wall of text”, then it is already minified. Developers will often put ‘.min.’ in the filename to indicate this.
Another quick way to score a win is with Gzip or Brotli compression. This is like zipping up your CSS before sending it to the visitor, and the good news is that every web host should already have this enabled. If they don’t, maybe you need a better web host. But before you do anything that drastic, plugins like SWIS will automatically enable Gzip compression on your server for CSS, JS, HTML, and anything else that can be compressed. You can use the Network tab in your browser’s developer tools to confirm this. In the screenshot below, when we click on the JS file, we can see the Content-Encoding header is ‘br’ which stands for Brotli. Another good clue is that “34.1 kB transferred” (lower right) is far less than “91.1 kB resources”, which tells us the file was compressed.
CSS can also benefit from loading resources in parallel. Every browser and most hosting platforms support this out of the box. But the best experience here is with the HTTP/2 protocol (or higher), and that requires your site be delivered using HTTPS with a secure TLS/SSL certificate. Both have become pretty common-place, and if you’re not already benefitting from HTTP/2, ask your web host to see if they can help you with that. If you hit a road block with HTTPS, our video on encrypting your site should get you rolling.
The Black Sheep – Merge CSS
Don’t, just don’t… But if you must know, this goes back to HTTP/2 vs. HTTP/1.x. In the (distant) past, you could often get more speed out of your site by merging all your CSS into a single file. With HTTP/1.x, your browser could open multiple connections with the server to load resources in parallel. But opening multiple connections was kind of expensive on resources, so browsers limited you to 6 connections. If you need to load HTML, CSS, JS, images, and fonts, 6 connections is hardly enough. So smash all the CSS into one file, and the browser can ingest that more quickly…
Except now HTTP/2 is practically everywhere, and the built-in multiplexing allows parallel transfers on a single secure HTTPS connection. Combining CSS is also worse for browser caching and cache invalidation, which means if you change anything in your CSS (like after a plugin update), all your users have to re-download all of your CSS again. Boooo!
Herding Cats
That leaves us with three of the recommendations that can be the most difficult to implement. Or at least that used to be the case… First, we go back to “eliminate render-blocking resources”. With JS (JavaScript), browsers have a built-in defer mechanism that can be used. WordPress core even added support for this a while back so theme and plugin developers can defer JS without any plugins needed. That said, there are a ton of plugins that don’t defer anything by default, so you probably still need a plugin to round up the stragglers!
What about CSS though, can’t we defer that? Well, sort-of, but not using any standardized method. Our SWIS Performance has a CSS optimization feature that will defer CSS, as do most performance plugins, but there’s a catch. It’s the reason there’s no built-in method to defer CSS. See, you can’t defer CSS and display a web page at the same time. If the browser tries to display your page before the CSS loads, it will look very strange, and as the CSS loads, stuff will start to bounce around, shifting and moving here there and everywhere. We often refer to this mess as FOUC, a “flash of unstyled content”.
We now have a second recommendation to “fix” the first one. To get around the FOUC, plugins like SWIS need to generate “critical path CSS”. That is, we need to know what CSS is critical to display the portion of the page that the user will see initially (aka “above the fold”). We can inline that critical CSS directly into the HTML of the page, and then load the rest of the CSS right after the page is rendered. This results in snappy pages, and we don’t have to worry about the rest of the CSS, right?
Thinning the Herd
Right??? Well… maybe we should take a look anyway. The third recommendation that you’ll see frequently is “Reduce unused CSS”. Sure, that makes sense, no need to load junk we aren’t using. However, unless the savings are better than 100kb, you’re better off just stopping right here. The amount of work involved in reducing unused CSS is often not worth the amount of time you’ll spend. GTmetrix will flat out tell you “This is an advanced-level optimization. Developer support is strongly recommended.”
Wait a minute though, are we going to give up so easily? After all, maybe you’ve seen that WP Rocket has this handy one-click Reduce Unused CSS feature. But does it make your site faster?
Versus
We’ve had a bunch of folks ask us to add a similar feature to SWIS Performance, and it sounds really slick. Just check a box, and no more unused CSS! As I alluded to at the beginning, WP Rocket lets you choose one of these two methods to Optimize CSS delivery. Load CSS Asynchronously mirrors the process we talked about before, deferring CSS and inlining critical path CSS.
Remove Unused CSS runs a similar process, but looks for all the CSS needed to render the entire page instead of just the “above the fold” portion. Then, WP Rocket inlines all the used CSS, just like it would for critical CSS, but then it eliminates all your external CSS. You’ve already got everything necessary to render the page right in the HTML, so no more CSS is needed. Of course, this doesn’t work with every plugin out there, so in some cases you may need to exclude a CSS file or two.
Now what could possibly be wrong with that, why don’t we just add it into SWIS right now?! First, building such a thing is an enormous undertaking. Just ask one of the WP Rocket engineers how many man hours went into making that happen, and continue to be spent fixing the bugs they run into, not to mention maintaining a fleet of servers to scrape pages and find the used CSS for every single page on your site. Second, what could go wrong? Just ask WP Rocket, they have the docs to prove it.
Faster?
Despite all my misgivings, what if it just works? So lets back up and ask why we’re doing this? Both PageSpeed Insights and GTmetrix tell us “to decrease bytes consumed by network activity.” That is, it saves us, and our customers bandwidth. In comparison to the amount of bandwidth saved by image optimization, the amount saved by reducing unused CSS is minimal. Blink once and you’ll miss it. Maybe it could actually make your site faster though?
Well, there’s a good reason it might not, and it’s the main reason I’ve waited 3 years to even investigate this functionality. Browser caching. I mentioned it earlier, but when someone first visits your site, they get all your CSS files, and then it keeps them for every page they visit. The main reason we make our sites faster is to keep folks on our sites longer. We want them to read more articles, or signup for our service, or buy one of our products.
Inlining the used CSS and removing everything else makes it completely impossible to cache ANY of the CSS for your site. Every single page will contain it’s own CSS, much of which could be duplicated. In contrast, if we load all our CSS once, the visitor never has to load another CSS file from our site again… at least not until a CSS file changes. And even then, they only need to load the bits that have changed, and then the browser cache will be up to date again.
Coming Back to Earth
That’s all well and good in theory, but how does it actually play out? I took a look at a bunch of my own sites to find the best test case that will properly illustrate browser caching. I have sites running all sorts of different plugins and builders, Kadence, Genesis, Divi, Elementor, and so on. But the site with the most CSS is the unoptimized version of ewww.io. That is, our site without using Slim to remove unused CSS. The main reason for this is the number of plugins involved.
On most of my testing sites, there aren’t many plugins active, just the builder with a demo page (or two), so none of those make for a good test of browser caching. This also tells us that most page builders are already doing a pretty good job of keeping the CSS to a minimum. I do have one other demo site that has a slew of plugins that almost qualified for testing. It has 170 kb of CSS from the theme, builder, and plugins, but it doesn’t have enough pages to properly illustrate the benefits of browser caching.
The Setup
I tested WP Rocket on a clone of our site with both methods of optimizing CSS delivery on 5 different pages. It was a bit time consuming, so I only did 3 tests on each page. Each time, I started with a fresh browser cache using Incognito mode and loaded all 5 pages to see the impact of browser caching. I’m measuring the “DOMContentLoaded” time, which is the closest to how long it takes before the page is rendered and the visitor can see it. The Weight in this test is only the HTML, since there is no CSS loaded at all. Here are the results with Remove Unused CSS:
Page | Test #1 | Test #2 | Test #3 | Weight |
---|---|---|---|---|
Homepage | 1.280 s | 1.18 s | 1.10 s | 40.3 kb |
Features | 724 ms | 387 ms | 385 ms | 35.9 kb |
Pricing | 299 ms | 290 ms | 329 ms | 37 kb |
Blog | 350 ms | 271 ms | 277 ms | 34.2 kb |
Contact | 387 ms | 404 ms | 316 ms | 32.9 kb |
Next, I switched the site over to Load CSS Asynchronously and made sure WP Rocket was finished generating critical CSS. This time, we have two numbers for Weight: the page HTML (with inlined critical CSS), and the external CSS.
Page | Test #1 | Test #2 | Test #3 | Weight |
---|---|---|---|---|
Homepage | 1.35 s | 1.22 s | 1.38 s | 26.4 kb + 101 kb |
Features | 454 ms | 781 ms | 356 ms | 23.2 kb + 0 |
Pricing | 340 ms | 268 ms | 401 ms | 23.8 kb + 0 |
Blog | 328 ms | 525 ms | 293 ms | 22 kb + 0 |
Contact | 298 ms | 288 ms | 470 ms | 21.3 kb + 0 |
Lastly, I took the combination of our site (ewww.io) with all the unused CSS removed by the Slim feature in SWIS Performance, and the Critical CSS + Optimize CSS loading in SWIS to see how our current stack compares. In this case, “unused CSS” is any plugin CSS that is completely unused on the various pages. This time, you’ll see we loaded external CSS on the first two pages, because the other pages use some CSS that is not used at all on the home page.
Page | Test #1 | Test #2 | Test #3 | Weight |
---|---|---|---|---|
Homepage | 1.02 s | 1.09 s | 1.03 s | 27.9 kb + 50 kb |
Features | 630 ms | 468 ms | 464 ms | 24.2 kb + 22 kb |
Pricing | 404 ms | 357 ms | 308 ms | 26.8 kb + 0 |
Blog | 375 ms | 368 ms | 286 ms | 22.7 kb + 0 |
Contact | 304 ms | 367 ms | 383 ms | 22.1 kb + 0 |
Comparison is a Thief
But we have this data, so we need to compare it anyway! Here’s the reality, all of these results are good, and we’re back to the big question. Did WP Rocket’s Remove Unused CSS make the site faster? No, it really didn’t. The absolute fastest load time was actually with critical CSS at 271 ms, but at these speeds, a butterfly flying by could cause (most of) the differences we are seeing. The only small difference was on the very first page load, because we have 100kb of CSS to load instead of the 14kb inlined in the HTML.
Our page optimized with SWIS is even faster on that first page load, and practically identical everywhere else. So I have to ask myself, “Why would one implement a feature to automatically remove unused CSS?” I won’t presume to know exactly why WP Rocket invested thousands of dollars into this feature, but if it isn’t for speed, the only other reason to do this is to get a better PageSpeed score. That’s not to say it can’t make some sites faster. Again, I’m not trying to say WPR only did this to game the scores. But if we did it, that’d be the only valid reason, and that isn’t how we roll. We’re here to make your site faster. So…
What is it good for?
For some reason, that makes me think of the song War, in which the answer was “absolutely nothin'”. We like to rag on Google’s PageSpeed Insights, because higher scores don’t always equal faster sites. Besides which, it’s really good at pointing out how bad Google’s own products are for your site speed, and Google doesn’t even follow their own recommendations.
But to Google’s credit, it seems they have some good advice here:
Specifically, “A plugin should only enqueue a stylesheet if it is actually used on the page.” Unfortunately, that’s not easy for plugin developers, as I know from first-hand experience. The hoops one has to jump through to manage such a thing are so complicated that I’ve done it, and I can’t even remember how I did it. CSS is loaded in the head of the page, but a plugin won’t typically know if it is used on a given page until the content of the page. By then, it’s too late to not enqueue a stylesheet, so odds are, they aren’t going to bother.
Go Fish!
If your plugins aren’t going to do this, then should you bother? We typically see two goals here: make our site faster so it’s a better experience for our visitors, and improve our search engine ranking. The latter is highly questionable, with Google themselves stating that page speed is only one of many page experience signals used in ranking, and page experience being only one area of the ranking algorithms. There are literally hundreds of ranking signals, and so a small savings in unused CSS is not going to help you rank better.
So we’re down to making the site better for our users, which is a fantastic idea, and the reason EWWW IO (and SWIS) exist. If you have WP Rocket, and their approach makes your site faster, measured the right way with real world testing, use it and don’t look back. Otherwise, the tools in SWIS are the best combination to make our pages feel nice and snappy AND eliminate unused JS/CSS with Slim.
That said, Slim is a power tool, meant for power users. Unless it’s going to make life better for your users, stick with optimized/deferred CSS and Critical CSS. If you really want to try Slim, but it overwhelms you, stop and come back to it later. It’ll be right there waiting, when you have the time to learn how to remove unused CSS the best way.
How much polish?
Ultimately, it all comes down to how much time you can afford to spend on a site. SWIS gives you the tools to make quick wins on your site with page caching, Gzip encoding, browser caching headers, optimized loading for JS/CSS, critical CSS generation, and font optimization. But it also gives you the power, with Slim, to trim a site even further IF it needs trimming. Otherwise, it’s like a body-builder trying to trim the fat, an exercise in futility. Keep your eyes focused on the goal, delighting your visitors and customers, anything else is just extra.