Love seeing how a small change can make such a big impact.
Can I suggest an alternative that might be worth testing over the base64 encoding of the image?
Instead of reducing the number of round trips by encoding the image in base64, reduce the number of round trips by inserting your header.css directly in the <head> of your document.
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<link rel="stylesheet" href="dist/css/bootstrap.min.css">
<link rel="stylesheet" href="dist/css/custom.min.css">
With this version, your browser can parse the CSS straight away rather than fetching it and then start downloading the image file (which can also be cached) while moving on to start the download and parse of the bootstrap.css file too. With the base64 image you still have to download and parse the CSS, even if the CSS is mostly one image.
I'd be interested to know if that made a difference too.
That's a great suggestion, and I'll have to give that a try. I've no doubt that it will be much more well optimised than my solution of using a base64 image.
The one thing that would stop me from doing it in a "release" application would be that I really don't like using inline styles. It's not easy to change them globally (though in this example, it's pretty simple to do so).
My other reason for avoiding inline style blocks is that I've already added a CSP to this project, and it would mean adding either 'unsafe-inline' (which is horrendous for security) or a 'sha-...'/'nonce...' for the 'style-src' directive. I don't mind doing either, but when the inline style blocks change I'd have to remember to change the CSP.
I followed your advice, to see how the inline styling affected the page load times. Here is the page with the inline style block:
And here is the base64 version:
I'll have to make more changes to the way that the page is structured if I'm to use the inline style block I'm sure, and this was a really quick test (literally changing the one line, pushing to my test environment, and refreshing). But I'm looking forward to trying this again when I have more time
I like the look of the waterfall with the inline style! Though I can't see total page load time, it looks like it's an improvement.
You'd be surprised how many sites embed what they call the critical CSS (enough to style the initial page load above the fold) into the <head> of the page. Some of the faster sites in the world use this technique, places like the Guardian, the Financial Times and even this site.
It stems from the work that many in web performance did a few years ago based on the critical path to displaying a web page, something you are talking about in this post. Namely that CSS must be downloaded and parsed before a browser will continue to render a page. For much more detail on this, and some real life results too, I recommend this talk by Patrick Hamann on CSS and the Critical Path. Then, for a bit more information on how you might go about implementing this, this post on Smashing Magazing by Dean Hume shows some techniques for using critical CSS. That might not cover tools that are in your toolchain, but it might give you some ideas. Particularly that it shouldn't necessarily change the way you write your CSS, but it may change that way that you serve it.
I understand the CSP issue, but it should be fairly hard to write insecure CSS and if you do go through the work to split up your CSS by critical and non-critical, it should follow that you can generate the sha hash required to satisfy your CSP.
I am fascinated by web performance and seeing how techniques like this work as well as their real world results. Let me know if you do investigate this further!
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.