Traveling around Asia has taught me that it's not enough for a service to work good on fast fiber connections. At some places, my own services would give me a horrible experience because of the bad connection. I felt obligated to fix this somehow and therefore put other stuff on hold until I could deliver a great experience, even on bad connections. This post will describe some of the changes I've made to Klart so far.
Klart, like many other web applications displays a listview of posts with images, allowing users to click for details and a larger image. All these preview images has to be requested from the server to be displayed, even in the listview. That's a lot of requests. There are different approaches of how you can reduce the number of requests. For example, Dropbox sends multiple pictures in one request using base64 strings to bring down the number of requests. For Klart I started with just lazily loading the images, meaning I would only request them when needed (close to or in user's view). This turned out to be sufficient when on a good connection but a bit dull with slower connections. Since I used the original images in the listview, these would be quite large (~1-2MB). Thus, the search for optimized images started.
Search for the perfect format
I spent a lot of time comparing different quality pngs ang jpegs, going through hundreds of image samples. Now, jpegs couldn't deliver the same quality as pngs and there would be visual artifacts on almost all samples but I decided to give it a go anyway since the size would be reduced drastically which might weigh up the slightly worse quality. But I was wrong.
Two days in I heard from a user that the images wasn't as crisp now as before, and she asked why. I answered that it was a tradeoff between speed and quality and that I was trying this out. But I could feel that it wasn't the right decision. I had felt it too. Klart was created with quality as number one priority. If you save design inspiration, it better be in the best format and quality possible, no trade-offs. I reverted quickly and went back to the drawing board.
A common approach for showing a listview is to use smaller images and then request the larger image on click. I like this approach, although you would either have to resize images on request or save smaller copies of the images. Anyway, I decided to give it a go.
Size of the request were, as expected, reduced significantly and images were shown way faster than before on slow connections. It also seemed to be no more problems when I was trying it from a decent connection. But once again when I tried using a worse connection, problems would appear.
Before thumbnails, when I always displayed the original image, the larger image would be displayed instantly on click (since it was already fetched). When I started using thumbnails for preview, the browser had to make an additional request on click to load the bigger image. Consequently, the user experience still wasn't any better than the original approach. This might be solvable by making background requests for original images, but then, what's the point?
A decision had to be made, should I use these smaller sized thumbnails or not? This is of course also a trade-off, and you have to consider your user patterns to decide what to go with. In the case of Klart, I often want to see the bigger image which pointed towards using only original images to leverage browser caching. Damn, I guess it was back to the drawing board again.
Now I was basically back to square 1, and I wasn't happy with it. I remembered that I've read something about Facebook manipulating jpegs to display a blurred preview of cover photos. I decided to look into it. It turns out that they managed to shrink small thumbnails of cover photos down to 200 Bytes by creating a fixed jpeg header stored on the client. This way they could send the actual image together with the other data, without needing additional requests to display the preview. Now, this was something I could work with.
I read up on the jpeg format and header, started to experiment with sizes and headers for different image samples. Sadly though, I couldn't really get to where I wanted, and since I'm not a big company, I didn't have more time too put into it. I decided to scrap it and look for other solutions.
Formats Formats Formats
I tried low quality jpegs and pngs but they always turned out to be a bit big compared to their quality. Then I found an article that used low quality gifs instead and I decided to give it a go. It turned out that I could resize the original images to 3x3 pixel GIFS which would result in a size of just 63 Bytes. I spent a considerable amount of time experimenting with size of the GIF for different samples to find one that gave a good experience when blurred on preview. Turns out that 3x3 was quite enough. Now I could store these thumbnails as base64 strings in the snap JSON documents. **This meant that I could display the previews instantly, giving the user a nicer experience, greated with colors 🌈 and buying some time to fetch the high quality images when needed **.
This is what it looks like now. I'd love to hear your thoughts about it 😊 !