There are a lot of recommendations out there on how to make your website faster. It can be difficult to know which ones will help your site and which ones are just utter trash. While I typically focus on the top threat to your website performance (images), I want to tackle some common recommendations to speed up your JavaScript (JS) and Style Sheets (CSS).

I won’t rehash everything from the video, but I want to point out the highlights, and add some things I’ve learned about deferring CSS.

Gzip or Brotli?

This one is performance gold and will always make your site leaner and faster. If you have ever heard of using zip to make files smaller, this is the same, but for your website. If you haven’t heard of zip, crawl on out from under that rock!

Both Gzip and Brotli are server-side compression tools that can be enabled by your webhost, or even a plugin. Many CDN providers also have an option to enable this compression, or will have it enabled by default.

Minify JS and CSS

This is another great way to speed up your website. It’s so great, most plugins and themes will already include “minified” JS/CSS resources.

But if they don’t… there are plenty of plugins out there to do the job for you. Also, it’s a sneaky hidden feature of our Easy IO service. Minifying your JS and CSS files strips out whitespace, code comments, and any other unnecessary characters to make sure they are as small as possible.

Combine JS and CSS (for fewer HTTP requests)

It sounds great, right? Let’s mash all our code together, so the visitor’s device doesn’t have to request so many files. But this is one to be very cautious with, as modern web servers use a thing called HTTP/2.

Short version, if you’ve setup your site for https (you really should), and have a competent web host, combining files actually works against you. HTTP/2 introduced the ability for websites to transfer files in parallel. This isn’t limited to JS/CSS, but applies to images, fonts, everything!

So what’s faster: loading 2-3 large files, or 20 tiny files in parallel? The latter scenario wins out nearly every time, so do NOT combine your files if you use https. And if you still have not set up https, get it done already (coming in a future blog post)!

Defer render-blocking resources

This one may or may not make a difference for folks on desktops with fast connections. But for the 90% of your traffic that comes from mobile devices, this is critical. Yes, I made up that number, but you know what I mean!

All that fancy JS/CSS code ends up making the browser slow down the rendering process. This means your visitor has to wait before they can even view the page. It’s bad enough having images popping into the page 10, 20, or even 30 seconds after a page renders. But JS and CSS files won’t even let the page display until they are done loading.

To fix that, we can defer things like JS and CSS. It’s like lazy loading, to defer images until the user scrolls to them. Though, in this case, the JS/CSS files will still load, they just might not finish until after the page is rendered.

You can use the Async JavaScript plugin to defer JS (use defer rather than async), or use the EXACTDN_DEFER_SCRIPTS override in Easy IO. WP Rocket is another fine option to defer scripts, and can resolve most of the recommendations here.

What about CSS?

Bonus content for anyone who made it this far! WP Rocket will defer CSS with their Optimize CSS Delivery option, but if you’re like me and love to tinker, I’ll show you the best method I could find. Otherwise, skip down for Inline All CSS…

While Google has a great method that works in most browsers, it doesn’t work in Firefox (which people do still use). This one is similar, but let’s say you have this CSS reference in your page:

<link rel='stylesheet' href='https://www.example.com/wp-content/themes/twentytwenty/style.css' media='all'>

You can simply change the media attribute to ‘print’ and the browser will still load it. Once it loads, a tiny bit of JavaScript changes it back to media=all, and the CSS is active on the page! It looks something like so:

<link rel='stylesheet' href='https://www.example.com/wp-content/themes/twentytwenty/style.css' media='print' onload="this.media='all'">

The only downside to this is that the priority of the CSS loading is decreased. So if we want the CSS file to load just as quickly as it would normally, we can add one more line:

<link rel='preload' href='https://www.example.com/wp-content/themes/twentytwenty/style.css' as='style'>
<link rel='stylesheet' href='https://www.example.com/wp-content/themes/twentytwenty/style.css' media='print' onload="this.media='all'">

Critical CSS

One thing to watch out for is a FOUC. What’s a FOUC??? It’s the dreaded “flash of unstyled content”. When CSS is deferred, your page will render unstyled, and then get styled as the CSS files load.

To avoid this, we inline our Critical CSS. Again, WP Rocket can do this for you, though they don’t automatically include mobile-specific rules. If you have a responsive theme (and I hope you do), that might not be good enough.

So I inlined my CSS manually in my child theme. Yes, it took way too long! There are other tools that can do this for you, but I’m a bit OCD and wanted to have it as close to perfect as possible.

Manually finding Critical CSS

First, I found all the active/critical CSS rules for a desktop screen, and for mobile devices (using Chrome’s mobile simulator). See How to Identify Critical Resources at https://web.dev/render-blocking-resources/

Then, I put all the CSS in my child theme’s header.php. You can also use Autoptimize or WP Rocket to include your critical CSS.

Lastly, I eliminated any rules that didn’t affect above-the-fold content on my page(s). I disabled all my CSS files using WP Gonzales and then tested each unique layout on my staging site. This way, I could compare it to the live site to make sure I had all the critical rules (and didn’t remove any of them accidentally).

Defer CSS Code

Here is the code I used to defer all my style-sheets, inserted into the functions.php of my child theme:

function my_child_theme_async_css( $tag ) {
        if ( false === strpos( $tag, 'preload' ) ) {
                $async_tag = str_replace( "media='all'", "media='print' onload='this.media=\"all\"'", $tag );
                if ( false !== strpos( $tag, 'wp-content/themes/' ) && false !== strpos( $tag, "rel='stylesheet'" ) ) {
                        $async_tag = str_replace( "rel='stylesheet'", "rel='preload' as='style'", $tag ) . $async_tag;
                }
                return $async_tag . '<noscript>' . trim( $tag ) . "</noscript>\n";
        }
        return $tag;
}
add_filter( 'style_loader_tag', 'my_child_theme_async_css' );

That’s a whole lot of work, and there were a few times this next recommendation started to look mighty tasty!

Inline All CSS

This one is pure and utter rubbish… 99% of the time! Look, we already talked about why you shouldn’t (normally) combine your CSS, and the same logic applies here.

One huge resource loads slower than 20+ tiny resources, even with all the overhead of DNS and HTTP requests. Unless your entire page, CSS and all, has less than 14kb of code, it just isn’t faster to inline all that CSS. And if your site has less than 14kb of code, it probably looks like rubbish too, unless you’re some CSS wizard. But even then, it probably still looks like trash.

Milica Mihajlija over at Google says it very nicely:

Keep in mind that if you inline a large amount of CSS, it delays the transmission of the rest of the HTML document. If everything is prioritized then nothing is. Inlining also has some downsides in that it prevents the browser from caching the CSS for reuse on subsequent page loads, so it’s best to use it sparingly.

https://web.dev/extract-critical-css/

Certainly, inline all your critical CSS, but no more than that. Sure, it might trick Google into removing that pesky “defer render-blocking resources” recommendation, but it doesn’t speed up your site.

Speed vs. Scores

Too often, folks start implementing all these crazy things just to boost their score on a performance test. But remember, the performance test isn’t your visitor. Everything you do on your site should be with one goal in mind: making your site a better experience for your visitors.

A faster site is a better experience, while a site that scores 100 on a speed test could still be better off in the trash heap.

So try out each recommendation, see if it makes your site faster. If not, then don’t do it just because I said so, or even because it’s on Google’s fancy list of recommendations. Go out and make your site a better site for your audience, your customers, your guests.