Turtles all the way down

A presentation at HalfStack at the Beach in July 2022 in Newquay, UK by Niels Leenheer

Slide 1

Slide 1

Turtles all the way down

Slide 2

Slide 2

It is great to be here in Newquay. I just love the talks so far. Halfstack is just a little bit different than most other conferences. There is room for some topics you wouldn’t see anywhere else. And I love that.

Slide 3

Slide 3

But now something serious. Dylan, the creator of HalfStack started a new company and that means he is very very busy. So I decided to help him out and optimise the Halfstack website for him. Free of charge.

Slide 4

Slide 4

So, the first thing I asked myself, is where do I start. So I decided to take the scientific approach and do a comparison

Slide 5

Slide 5

Of course you need a good large, representative data set to get significant results. But I did not have that much time, so I just picked two. My own website and some random other website. And you can plainly see that that website is clearly a lot slower. 80 times slower. And it has more than a 1000 requests compared to my 11. Lots of trackers and lots of images.

Slide 6

Slide 6

So we’ve scientifically established that websites that make more requests are slower.

Slide 7

Slide 7

And we can also tell that external images require requests to fetch them from the server.

Slide 8

Slide 8

Combine these two premises and we have a conclusion that by inlining images we can make a website faster.

Slide 9

Slide 9

Now back to our website, you’ll notice there is definitely room for improvement.

Slide 10

Slide 10

There is one obvious candidate for optimisation.

Slide 11

Slide 11

Our logo. The space it takes is 240 by 150 pixels.

Slide 12

Slide 12

But nowadays we have high resolution screens. So we need at least a 2x image for the logo to look good. This logo requires a request. And on every page. So let’s try to inline that image so we avoid that request.

Slide 13

Slide 13

But how do we do this…

Slide 14

Slide 14

Well, an image is just a raster or grid of coloured pixels.

Slide 15

Slide 15

And tables are kind of like grids…

Slide 16

Slide 16

So we can use tables for inlining images. Obviously.

Slide 17

Slide 17

So, a table with a cell for each pixel. Almost 150 thousand cells. And because we don’t want to mix styles with content we are going to use…..

Slide 18

Slide 18

So, a table with a cell for each pixel. Almost 150 thousand cells. And because we don’t want to mix styles with content we are going to use….. Eh images? For every single color we’re going to generate a 1 by 1 pixel spacer image.

Slide 19

Slide 19

That is 16.7 million image files x 88 bytes = 1.35 GB. But about 80% along the way of generating these images something in the filesystem broke. Apple claims you can put 2.1 billion files in a directory. But that is not true. Your Mac will crash. It will fail to boot and you need to start it up in rescue mode do disk repair and delete the whole directory from the Terminal before you can use your computer again.

Slide 20

Slide 20

So… lets just use a background color and then a transparent spacer image. Times 144.000.

Slide 21

Slide 21

And it works….. The HTML is just 7.1 MB and it “only” took 9 seconds to render. But still 1 request. So we can do better.

Slide 22

Slide 22

Data URLs for the spacer images.

Slide 23

Slide 23

Of course that means our HTML will be bigger. And rendering times will go up too. But now we have zero requests…. We are done!

Slide 24

Slide 24

Well… we could just use HTML4 attributes like width and height to replace our spacer image. HTML4 is just better than HTML5 that way.

Slide 25

Slide 25

So now 6.3 MB and down to 3 sec.

Slide 26

Slide 26

But 3 seconds is quite long. So how can we optimise the rendering?

Slide 27

Slide 27

Just think of web workers. Parallelisation improves performance.

Slide 28

Slide 28

And frames are kind of rendered independently from each other.

Slide 29

Slide 29

So let’s inline images using frames instead.

Slide 30

Slide 30

Problem one. There is no documentation. Not in the spec. Not on MDN. So I headed over to the trusty W3schools and yup. All the info I needed.

Slide 31

Slide 31

An iframe that shows a document with frame sets and 144.000 frames. And HTML documents for each individual color. What can go wrong?

Slide 32

Slide 32

Yeah, lessons learned from spacer images. Let’s just inline those documents.

Slide 33

Slide 33

And apparently there is a 1.000 frame limit… we need 144.000.

Slide 34

Slide 34

So let’s try a different approach. SVG is easily embeddable. So in theory this should be perfect.

Slide 35

Slide 35

So every pixels is basically a small rectangle that we position using x and y attributes.

Slide 36

Slide 36

Brilliant. Just 2 seconds. This is way better than tables. Tables are shit. Don’t use tables.

Slide 37

Slide 37

So let’s try a different approach. CSS. You can even recreate paintings with just CSS, so our logo should be easy.

Slide 38

Slide 38

Absolute positioning. A div with an id for each pixel. And using CSS to set the position and the color.

Slide 39

Slide 39

Larger size as SVG and slower… Hmmm….

Slide 40

Slide 40

So let’s try pseudo selectors. First pixel is a single ::after. Second is two times :after. Third pixels is :after:after:after. And so on.

Slide 41

Slide 41

Well, that didn’t work. I actually ran into an issue with generating. The file is 37 GB big. And even though the maximum string length in Javascript is 8192 Terabytes, V8 can’t handle strings that long. The positive thing is, gzipped it is only 62 MB….

Slide 42

Slide 42

But now we have CSS grid. So let’s try that. And instead of Id’s use the nth-child pseudo selector.

Slide 43

Slide 43

Eh…. oops. Apparently nth-child is not really optimised.

Slide 44

Slide 44

After 21 minutes it stopped rendering. Not sure what the problem is with the rendering, but without nth-child and back to Id’s it still took 59 sec but at least it looks correct. Grid is slower than absolute positioning.

Slide 45

Slide 45

But what about box shadow? So if you have a 1 by 1 pixel element and give it a background color.

Slide 46

Slide 46

You can give it a shadow. And position it right next to the original element.

Slide 47

Slide 47

But you can add multiple shadows on the same element. And you can position each individually and give each it’s own color…

Slide 48

Slide 48

Do you see where I am going with this…

Slide 49

Slide 49

So this box-shadow CSS property is 3 MB big. It has 139.999 shadows in one declaration. But that is only 380 KB gzipped and rendering took only 0.1. So this is. Box Shadows!



Slide 50

Slide 50

But we have a lot of dark blue here. What if we don’t include that in the shadows itself, but just set a background color on its parent.

Slide 51

Slide 51

We’ve gone from 18MB to 604KB and from 13 seconds to 40 ms. A big improvement. Success! And while 604 KB still sounds a lot. It is still less than the average size of a banner ad on the website of the Express. And I kid you not, they spend more time waiting for the server to respond than we spend to render the image.

Slide 52

Slide 52

So what are the key takeaways from this talk. What are the things that you can use in your projects next week.

Slide 53

Slide 53

HTML4 is better than HTML5.

Slide 54

Slide 54

Use divs for everything except when you can use shadows, of course.

Slide 55

Slide 55

The maximum length of a string is nine quadrillion , seven trillion , one hundred ninety nine billion , two hundred fifty four million , seven hundred forty thousand , nine hundred ninety one bytes.

Slide 56

Slide 56

And w3school is much more complete than mdn. Mdn is good for that fancy new stuff, but if you want the good stuff like frames, blink and marquee, you’ll need w3schools.

Slide 57

Slide 57

And don’t use 144.000 frames in one frameset. Split them up over 144 framesets of a 1000 frames each.

Slide 58

Slide 58

I must admit that I am slightly annoyed that apparently they changed to logo, so that means I can completely start over. So I hope you learned some useful information here. Learned some new skills. And with that I just want to say thank you and let’s make inlining images a top priority.