Square Thumbnail Solution

Since JaL Productions v3, I’ve been experimenting with different solutions to square thumbnails.

My ideal solution is that all the thumbnails are automatically generated from the source images, perfectly aligned at all screen sizes and do not hinder browser performance.

The problems

The initial problem with square thumbnails is that the majority of the source content I am pulling in is not of a 1:1 width/height ratio. This means I have to have some way of aligning the images into a square container without letter-boxing, pillar-boxing or the thumbnail being misaligned or cropped.

letter-boxing | pillar-boxing | misalignment

letter-boxing | pillar-boxing | misalignment/cropped

The second issue to take into account is browser performance. There are plenty of ways to generate and lay out square thumbnails using Javascript or PHP, however I am placing a lot of emphasis on how they will effect browser performance and page load times.

The last issue is that of browser compatibility, and which solutions will hinder certain browsers.

The solutions

1. JaL Productions v3

I used CSS3′s background-size: cover; to crop and align my thumbnails inside a wrapper <div>. This was the solution for perfectly presented thumbnails, however it came with problems.

Firstly, the obvious CSS3 browser support. This was especially relevant for v3 as I built that in 2012, when CSS3 support wasn’t as great as it is now.

Secondly, this solution was semantically bad. I was presenting a bunch of images in <div> tags. This meant there was no support for image-specific context menu items such as Save Image As. It also meant that crawlers would not pick up these images, such as if I shared a link to that page on Facebook, it would not find any of the thumbnails. So when I started building v4, one of my requirements was that the thumbnails had to be <img> tags.

Thirdly, through my lack of knowledge, I was setting the width of my thumbnails using % in the CSS, and calculating the height in Javascript every time the browser was resized. This was a massive performance hit (especially for IE) and was before I knew how to create responsive squares in pure CSS.

2. JaL Productions v4 – The current solution

After working in the responsive team at the BBC, I became very aware of support for non-Javascript devices, and decided to rebuild my site to be completely mobile first, with support for devices without Javascript.

In order to provide properly cropped and aligned thumbnails for all devices, I looked into using PHP to determine the orientation of the thumbnail and settings its width and height accordingly.

I created a function called getOrientation() which uses PHP’s getimagesize() function to determine the image’s width and height, and from that its orientation. A class of either landscape or portrait is then applied to each image and then CSS is used to set the height or width respectively to 100%. This ensures the image completely fills the wrapper div without letter- or pillar-boxing.

The problem with this solution is that the getimagesize() function is too slow, and means that the initial page load time, before anything is drawn to the screen, is very long. This is not specifically the function being slow, it’s the roundtrip time for PHP to request all the images from the server. I am also requesting all the images one-by-one, meaning that each request also has the request header overhead. Not good!

Once the page has loaded, although the images fill their wrappers, they are still misaligned to the default left positioning. I’d much rather the centre of the image be shown in the thumbnail. So I use Javascript to calculate the width/height of the wrapper and the image (depending on the orientation) and re-position the image inside the wrapper accordingly using negative margin. I also use Ben Alman’s debounce plugin to limit the alignment recalculation to only when the browser has stopped changing size. This greatly improves the performance on older browsers.

So using this method, non-Javascript devices get a reasonably sized thumbnail that just isn’t perfectly aligned, and devices that do have Javascript will receive perfectly sized and aligned thumbnails even when the browser is resized, however the cost of this is a longer page load before anything is shown on the screen.

Rethink

I am now in the process of revisiting my square thumbnail solution and I feel that I was blinded by the mobile-first approach that I was aiming for.

For every website that a developer builds, we should be considering the potential users who will be visiting our site. Now, although mobile-first seemed like a nice idea to showcase my skills as a developer, I think that it is hindering the performance of my site for a set of users that I simply don’t have or shouldn’t really be catering for. 99% of visitors to my site are going to have Javascript enabled, so why am I still trying to support them, especially if it hindering page load performance that much? Time for a change I think!

3. Speed up the PHP

The first thing I thought of was to run some benchmarks on the PHP side of things and see if there was a faster way of getting the image’s orientation. I found that PHP’s imagesx() and imagesy() would be slightly faster than getimagesize() for getting the image’s width and height, however the roundtrip request time is the factor that is really killing the page load time. I also found that using getimagesize() in a loop doesn’t do me any favours either, and that using something like curl-multi-init to do multiple requests simultaneously would be much more beneficial.

4. Imagick

The next solution I thought of would be to automatically generate all my square thumbnails. This would remove the need for getOrientation() and for any Javascript realignment after page load and on browser resize.

I am using Imagick to automatically generate the square thumbnails using cropThumbnailImage(). I then write the generated thumbnails into a thumbnail directory on my server and serve them to the user.

The advantage to this is that when a new image is added, the thumbnail for that image only has to be created once by the first person who visits the page (which is most likely going to be me anyway). My script checks whether the thumbnail already exists before generating one, kinda like a cache, so the Imagick function won’t run if it doesn’t need to.

The only disadvantage is that the current script I have saves all the images into a sub-directory on the same server. The previous solution loaded all the thumbnails directly from DeviantArt’s multiple subdomains, meaning I’ve lost download parallelisation.

At the time of writing, this seems like the best solution as long as I can develop into my script a way of storing the generated thumbnails into different subdomains.

5. Pure Javascript solution

A lot of posts I have read advise against using PHP for image manipulation and recommend doing it all in the front-end. This would be in favour of progressive enhancement but would go against my original requirements of making v4 mobile-first.

The real question is: How much should I really care about non-Javascript devices?

If I built a pure Javascript solution, calculating the orientation on page load instead of in the PHP, the page would load a lot quicker, but non-Javascript devices would get a shoddy thumbnail experience. That’s not to say they can’t still click through to the original image, but the thumbnails will be indistinguishable.

For devices that do have Javascript, once the page has finished loading, the Javascript will kick in, calculate the orientation and resize and realign accordingly.

I think this will be a very “jumpy” experience for the user and I am feeling more and more against this solution the more I think about it.

Which solution is the best?

Fast load times vs. shoddy thumbnails

Perfect, square thumbnails vs. loss of parallelisation

Posted Saturday, December 7th, 2013 under Scrapbook.

Leave a Reply

*