“When I was younger, so much younger than today” and upset and full of vinegar about the state of the world, I’d say things like “CSS is the worst” (not really). Now, half a year later, older and wiser and more accepting, I’d agree to mellow down to “CSS is render-blocking”.
What this means is the browser cannot render anything until it has the CSS it thinks it needs, all downloaded and parsed. Blocked rendering is bad User Experience and it also affects negatively the FCP and LCP metrics that Google folks deem important.
Loading CSS as early as possible is ever so important. Normally CSS is discovered once the HTML is (even partially) downloaded and parsed. But we can do one better, thanks to the “hints” we can send with the HTTP2 headers of the HTML response. This way we tell the browser to start loading CSS ASAP without even waiting for HTML parsing and discovery.
Scary? Nah. I was able to accomplish this with 2 lines of code (or 3 if you’re an overachiever) on my old-school cheap Dreamhost shared hosting with Apache server running this WordPress install. Here’s how:
1. Make sure your host supports HTTP2,
2. Edit your
3. …and add two lines similar to these:
H2PushResource /wp-content/themes/phpied2/style.css H2PushResource /wp-includes/css/dist/block-library/style.min.css?ver=5.4.1
Make sure your host supports HTTP2
I use Firefox and Brave, most people use Chrome or Safari. Between the 4 there are 3 versions of developer tools and waterfalls. So let’s speak the lingua franca and use WebPageTest.org
Run a test on your site and look at the waterfall view. You can spot the HTTP protocol version when you click on the HTML file.
I ran a test on this site and here’s my view:
.htaccess is just a plain text file in the root of your site that can tweak some Apache configuration. Since I’m talking about Dreamhost, here’s their htaccess guide.
The two lines
OK, so what do you put in the
.htaccess? Going back to the test I ran I can see how 2 CSS files are preventing rendering.
Note how the blue bar (HTML download) has a dark blue section. This is HTML parsing. And immediately after it, the 2 CSS downloads begin. What we want to do is move the CSS downloads to the left, so all rendering starts (and finishes!) sooner.
So all you do it take the URLs of these two files and add them to
H2PushResource in front. For me that means the URL to my custom theme’s CSS
/wp-content/themes/phpied2/style.css as well as some WordPress CSS stuff.
H2PushResource /wp-content/themes/phpied2/style.css H2PushResource /wp-includes/css/dist/block-library/style.min.css?ver=5.4.1 H2PushResource /wp-includes/js/wp-emoji-release.min.js?ver=5.4.1
Again, the JS is optional and not relevant to the render-blockage unblocking.
Here’s the waterfall before the change:
Here’s the waterfall after the change:
As you can see, in the “after” case the CSS download no longer waits for the parsing of HTML. As a result everything is faster – DOMContentLoaded, start render, onload, FCP, LCP. All the vertical lines happen 100ms sooner. Not bad for a few minutes of effort.
What happen as a result of these 3 lines of
.htaccess configuration is that the HTTP headers of the HTML now contain 3 preload links. That’s how the browser knows to go fetch CSS even before downloading and parsing HTML.
We can do better
We can. I cannot because the shared Dreamhost hosting doesn’t let me edit Apache config beyond
.htaccess. But if you have access to the server or virtual host config, see here.
Basically all you need to do in addition to what we did in
.htaccess is to add:
And that’s it. This will send a
103 Early Hints HTTP response with the CSS files even before the
200 OK response. Only in supported browsers, which is basically Chrome v103 for now (Get it? v103 supports 103 responses), this means that if WP is still working on the HTML response (e.g. fetching data) CSS can already start downloading. This is a huge improvement. For more, check this Twitter thread.
A picture says…
Here’s an attempt to represent these 3 cases “graphically”:
// #1 status quo connect ---> 200 OK header (no CSS hints) ---> HTML ---> CSS // #2 with hints as per this blog connect ---> 200 OK header (with CSS hints) ---> HTML ---> CSS // #3 with hints in a 103 response connect ---> 103 (with CSS hints) ---> 200 OK ---> HTML ---> CSS
Obviously #1 is the worst, that’s how it’s always been.
#2 described above with CSS hints is better.
#3 with the 103 response may be about the same as #2 if CSS is small and HTML is fast. But if the CSS is big or HTML is slow #3 may be a dramatic win. While the server is still checking databases and working on the 200 OK response the browser has had a chance to download and parse CSS and have it ready.
Take care now
Bye-bye then. Make the Web faster!
This content was originally published here.