Book a Consultation

What If?

Written by 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:

  1. immediately applying display: none; to the <body>;
  2. waiting until the very last of the page’s images had arrived;
  3. once they’d arrived, removing the 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:

  1. images being completely unoptimised, plus;
  2. a misconfiguration with their image transformation service leading to double downloads for all images;

…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:

  1. 5Mb up, 1Mb down, 28ms RTT. 


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.



Did this help? We can do way more!


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.


Suffering? Fix It Fast!

Projects

  • inuitcss
  • ITCSS – coming soon…
  • CSS Guidelines

Next Appearance

Learn:

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.