HTML Rendering: An Important Lesson

Jamie on January 22, 2019

Header image: Field notes and pencil by helloquence I put out a tweet at the weekend: dotnetcore.show @dotnetcoreshow That moment when you... [Read Full]
markdown guide
 

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.

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
    <style>
      #hero { 
        background-image: url('../img/header.jpg');   
        color: rgba(0,92,151,0.85);   
      }
    </style>
    <link rel="stylesheet" href="dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="dist/css/custom.min.css">
</head>

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.

EDIT:

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!

 

You are not using bootstrap from a CDN so you shouldn't split your CSS into multiple files. Concat bootstrap.css and custom.css so you only have 1 css to download. Also, remove unused CSS via purge.css or other tools.

Give this a try with your original URL based CSS solution.

<link rel="prefetch" href="img/header.jpg">
 

I really like the idea of using rel="prefetch", I hadn't even thought of that.

As for the CDN part, I'm currently trying to get this to be as fast as possible by hosting my own version of Bootstrap. I'm going to be looking into cutting out the stuff that I'm not using, so your tip about purge.css is greatly appreciated, too.

 

If your site is simple enough, ditch bootstrap. Nowadays it's not a huge help anyway.

Definitely.

If I was more well supported (i.e in Microsoft based browsers), I'd use flex grid because I've had a lot of success using it on my .NET Core Podcast website

95% for flex box :) More than enough.
88% for grid which is not that bad.

You can do most of the layouts via flex. But yeah, I can't wait to use grid for everything :)

Also, when you ditch bootstrap you can ditch jQuery, double win :D

Also, when you ditch bootstrap you can ditch jQuery, double win :D

Exactly this. I'm not a huge fan of jQuery and it's massive, so ditching that will reduce page load times by sooo much.

As an update to this: I spent a few hours re-writing the web app to use flex box with a few other optimisation suggestions here in the comments, and the application now renders (without a cache) in around 400-500 ms.

Just need to shave a little overhead off by utilising a better font. Maybe I should use Variable Fonts or something similar.

 

Wow, great job! I've always been rooted in the idea of having my one css file after bootstrap, and I never even considered splitting it up based on some smart loading.

Hm....need to run, I've got a couple tickets to write :)

code of conduct - report abuse