By Harry Roberts
Harry Roberts is an independent consultant web performance engineer. He helps companies of all shapes and sizes find and fix site speed issues.
Written by Harry Roberts on CSS Wizardry.
I was recently conducting some exploratory work for a potential client when I hit upon a pretty severe flaw in a design decision they’d made: They’d built a responsive image lazyloader in JavaScript which, by design, worked by:
display: none;
to the <body>
;display: none;
and gradually fading the
page into visibility.Not only does this strike me as an unusual design decision—setting out to build a lazyloader and then having it intentionally block rendering—there had been no defensive strategy to answer the question: what if something goes wrong with image delivery?
‘Something wrong’ is exactly what happened. Due to an imperfect combination of:
…they’d managed to place 27.9MB of images onto the Critical Path. Almost 30MB of previously non-render blocking assets had just been turned into blocking ones on purpose with no escape hatch. Start render time was as high as 27.1s over a cable connection1.
If you’re going to build an image loader that hides the whole page until all images are ready, you must also ask yourself what if the images don’t arrive?
This isn’t the first time I’ve encountered such an odd choice of development
strategy. A popular A/B testing tool does something remarkably similar: they
instruct developers to drop a <script>
block into the HTML page that
immediately applies opacity: 0 !important
to the <body>
element. While the
page is hidden, an external and synchronous JavaScript file is requested from
the provider’s origin. This external file contains all of the information needed
to run the A/B test(s) on the page, and once the file applies the test(s), it
then removes the opacity: 0;
. However, the fatal flaw here is that the file
responsible for showing the page again is separate to the file responsible
hiding the page in the first place.
This means that if the second file, for whatever reason, doesn’t make it onto the user’s device and execute successfully, we’ve left the user staring at a completely blank page. There are a number of ways that file could go missing: perhaps the third-party provider is suffering an outage; maybe the user has a third-party content blocker that strips out A/B testing software; what if the JavaScript is malformed and fails to execute? These are all things that could, do, and will eventually go wrong, so if you’re a developer who decides that you’re going to forcibly hide a page until an event has taken place, you must also ask yourself what if that event never happens?
While ever you build under the assumption that things will always work smoothly, you’re leaving yourself completely ill-equipped to handle the scenario that they don’t. Remember the fallacies; think about resilience.
This short post feels like a summary of several other things I’ve been trying to teach for the past several years, so I would encourage you to also read:
5Mb up, 1Mb down, 28ms RTT. ↩
Harry Roberts is an independent consultant web performance engineer. He helps companies of all shapes and sizes find and fix site speed issues.
Hi there, I’m Harry Roberts. I am an award-winning Consultant Web Performance Engineer, designer, developer, writer, and speaker from the UK. I write, Tweet, speak, and share code about measuring and improving site-speed. You should hire me.
You can now find me on Mastodon.
I am available for hire to consult, advise, and develop with passionate product teams across the globe.
I specialise in large, product-based projects where performance, scalability, and maintainability are paramount.