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
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
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
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
So we’ve scientifically established that websites that make more requests are slower.
Slide 7
And we can also tell that external images require requests to fetch them from the server.
Slide 8
Combine these two premises and we have a conclusion that by inlining images we can make a website faster.
Slide 9
Now back to our website, you’ll notice there is definitely room for improvement.
Slide 10
There is one obvious candidate for optimisation.
Slide 11
Our logo. The space it takes is 240 by 150 pixels.
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
But how do we do this…
Slide 14
Well, an image is just a raster or grid of coloured pixels.
Slide 15
And tables are kind of like grids…
Slide 16
So we can use tables for inlining images. Obviously.
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
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
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
So… lets just use a background color and then a transparent spacer image. Times 144.000.
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
Data URLs for the spacer images.
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
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
So now 6.3 MB and down to 3 sec.
Slide 26
But 3 seconds is quite long. So how can we optimise the rendering?
Slide 27
Just think of web workers. Parallelisation improves performance.
Slide 28
And frames are kind of rendered independently from each other.
Slide 29
So let’s inline images using frames instead.
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
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
Yeah, lessons learned from spacer images. Let’s just inline those documents.
Slide 33
And apparently there is a 1.000 frame limit… we need 144.000.
Slide 34
So let’s try a different approach. SVG is easily embeddable. So in theory this should be perfect.
Slide 35
So every pixels is basically a small rectangle that we position using x and y attributes.
Slide 36
Brilliant. Just 2 seconds. This is way better than tables. Tables are shit. Don’t use tables.
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
Absolute positioning. A div with an id for each pixel. And using CSS to set the position and the color.
Slide 39
Larger size as SVG and slower… Hmmm….
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
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
But now we have CSS grid. So let’s try that. And instead of Id’s use the nth-child pseudo selector.
Slide 43
Eh…. oops. Apparently nth-child is not really optimised.
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
But what about box shadow? So if you have a 1 by 1 pixel element and give it a background color.
Slide 46
You can give it a shadow. And position it right next to the original element.
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
Do you see where I am going with this…
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
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
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
So what are the key takeaways from this talk. What are the things that you can use in your projects next week.
Slide 53
HTML4 is better than HTML5.
Slide 54
Use divs for everything except when you can use shadows, of course.
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
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
And don’t use 144.000 frames in one frameset. Split them up over 144 framesets of a 1000 frames each.
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.