A little knowledge of html goes a long way


Now that my photography project looks pretty much how I wanted it to, I’ve turned my attention to polishing it and trying to get it to render quicker in the browser.

One of the reasons I’ve given this some extra attention is perfectly captured in the gif I made for the original post..

Look at the state of that white flash every time an image is rendered! I decided to do something about it, which involved revisiting the fundamentals of web development and the first language of most Myspace-using millennials, HTML.

What’s causing the white flash

FOUC

I believe what you’re seeing above is what’s known as a Flash of Unstyled Content, or FOUC for short. Ie., the browser either isn’t prioritising the image, the image is simply too big, or it’s being held up by another blocking process. All of those things were true in my case.

What I did about it

Reduce file sizes

Despite my original idea for the website in the first place it’s unrealistic to render the bloody gert raw image files in the browser and expect it to be snappy. For now though I’ve opted to resize the main image you see with a cap at around 2kpx width. For each photo I now store;

Black background

First things first, set the background to a more reasonable colour that fits the theme, in my case that’s black. That way if we do encounter a visible delay as a picture loads, at least it’ll be a black flash which matches the overall theme of the website, and not be so jarringly and obvious.

Prefetching and Preloading

You can get the browser to prioritise / deprioritise loading using these. For example, you can get the browser to cache the next page/items on that page if you know or predict what it’s going to be. In my case, that’s exactly what I need. The next photo is always pre-determined at the point that the current page is loaded, which means I can pre-cache the upcoming image, or the whole page if I want.

Preload loads that’s required for the initial render of the current page

<link rel="preload" href="{{ photo.url }}" as="image">

Prefetch loads content needed for the next page. In my case, the likelihood of the next page being the one visited by clicking on the main image is probably higher than any of the others links, so I’ll preload that in the background.

<link rel="prefetch" href="{{ next_photo.url }}" as="image">

Lazily load images

The thumbnails at the bottom of each page don’t need to load up-front. Here we have the opposite problem to the top image, we want to defer their loading by the browser until the priority assets have finished. We can add loading=lazy to each image so that the browser doesn’t fetch them until the user begins scrolling closer.

<img src="{{ p.thumbnail_url }}" loading="lazy"/>

Async Javascript

I’m still sticking the tags at the bottom of the body like it’s 2008, which to be fair to me is what Bootstrap still recommends in its docs. I should probably bundle this using the sass like npm but I haven’t yet. For now though, I’ve added async like this:

    <script src=".../dist/js/bootstrap.bundle.min.js" integrity="sha384xyz123..." crossorigin="anonymous" async></script>

Whether this is the optimum way of doing things or not I don’t know, but it’s had a positive improvement. I’m sure there are cases where this is the wrong thing to do.

Bundling fonts and other 3rd party assets

Got any google fonts being pulled? Bundle them up in your static directory. Simple as. You can reference them in your custom css like this;

@font-face {
  font-family: "Quicksand";
  src: url("../fonts/Quicksand-Light.ttf");
  font-display: swap;
}

#myId {
  font-family: 'Quicksand', sans-serif;
}

Inline CSS where it matters

The image that makes up the main feature of mylifein.pictures is a bootstrap container background. That means it relies on custom css, so if that css is buried somewhere in a link it could be loaded slower than if I’d included it inline.

    <div style="background-color: rgba(0, 0, 0, 0.838); background:transparent url({{ photo.url }}) no-repeat center /cover;"></div>

Misc help

The order of things

Just remember that if you’ve got a big image that’s being styled by some css which isn’t loaded until the very end, that the rendering of that image will probably be blocked. I’m sure there are exceptions to this, but it’s a good rule of thumb to keep in mind when you’re building.

Understand f12

Get used to looking at the network page of the debug menu. Under the network tab look for priority and size. What they’re telling you should be obvious, and it can prompt you to think about what the priority is before you start adjusting things in the DOM.

WebPageTest

Websites such as webpagetest are a useful tool. They scan your production website and give performance feedback and recommendations. As of today you get 300 tests per month on the free tier.

The End

I haven’t captured any metrics, but take a look at them side-by-side it’s an obvious improvement;

Before

After

FAUC-less.

These things are certainly all obvious to any web developer, but to a backend née data engineer who’s trying to simply get by on their own I expect a lot of these things aren’t so widely appreciated.

There are more things I can be doing. I’ll probably write this up on Medium eventually once I’ve grabbed some screenshots and maybe done a performance comparison on an old commit.

I’ve got a new appreciation for HTML, as I journey through the full stack from data lake to backend to front, I’m starting to come across these client side things I didn’t really have to think about until now.