Here at Casper, we’ve been working on our front-end performance, primarily focusing on reducing start render time and overall load time. A big factor that affects front-end performance is the amount of documents and assets being loaded on a web page. We’ve used variety of techniques to reduce the amount of assets being loaded when a user lands on the page like minifying the files we serve, compressing & caching images and recently we’ve added lazy loaded images to our home page.
Lazy loading is a pattern for loading content (in this context images) when it’s needed, rather than loading it all at once. This helps us decrease the amount unnecessary bytes being loaded for content that is not currently seen by the user (a.k.a. below the fold content)
One of the challenges of lazy loaded images is that if there’s no placeholder in position, the loaded images will then flash afterwards, making the page appear more slow to the user.
The pitfall that I’ve discovered is the fact that a few of the available lazy loading tools require me to specify a height or width in order to have a blank space for placing the image while it’s loading. Specifying a height is tricky because our images are responsive and their aspect ratios and dimensions depend on the size of the user’s screen or browser.
Other Placeholder Implementations
A common trick that I’ve seen in different implementations of placeholders for lazy loading is adding a
padding-bottom to the image container. It’s explained in detail in this blog post by David Calignano. The idea is to calculate the
padding-bottom by taking the
width of the element and calculating it:
padding-bottom: (height ÷ width) x 100
I’ve tried using this method with my progressive loading implementation and it worked perfectly, plus I can see it working well for pages that has defined a number of aspect ratios. But for our site this solution won’t really scale because we have a hundreds of images with different dimensions and aspect ratios.
As I was looking for solutions, I found the work done by José M. Pérez about lazy loading and creative placeholders for lazy loaded images. I was particularly interested in the examples he had in his progressive image loading blog post. The creative SVG placeholders were really cool and effective because SVGs are relatively small and theres a number of loading effects that can be done with SVGs — one of the examples used in the blogpost was a tracing technique. However the SVG animations are not supported by IE11 which is a browser we currently support, so I decided to use the blurry image placeholder effect for it’s simplicity and overall compatibility with different browsers.
For this lazy loading technique a small image is loaded at first (normally about 500 bytes) so that the page would have less bytes to load. A blur filter is applied to the small image and then stretched out to the full size of the original. The original image overlays and fades in on top of it.
My Placeholder Implementation
José’s example also featured the padding-bottom trick, but I figured that if the small image is already provided, expanding it would result in the same size of the original image. So I went to give it a try.
The markup contains both the placeholder and the link to the original image. The original image is being passed as a data attribute so that it is not immediately fetched when the page is loaded, this decreases the total amount of requests that our page is going to have to load.
In the CSS the placeholder is assigned to have a relative position so that the original image can overlay on top of it with an absolute position. The original image gets all it’s dimensions from the stretched out version of the placeholder image.
A simple css animation is also being applied using transitions to fade the original image on top.
The JS then does the fetch for the original image after the page has been loaded. This is where additional features can be added such as — when the user scrolls to an offset it could trigger an image to be loaded.
It adds a callback to the onload event that is called when the image has loaded. It’s then displayed on the screen after it’s fully loaded.
With this approach the padding-bottom did not need to be set on the container to serve as a placeholder. Provided the small image and the original image, the placeholder should calculate the correct dimensions of the image in any browser widths. It works seamlessly with images with different sizes and aspect ratios.
One of the drawbacks for this approach is all the additional CSS that had to be added to the image that’s being lazy loading. Different position properties are added to both the placeholder and the original image which can cause issues when the parent element heavily relies on different position properties. I’ve had to work with those types of scenarios but a few of them only needed a few minor tweaks on my end.
Given a really slow connection, the small placeholder images might take too long to load therefore possibly rendering a poor user experience. This is why it’s important to load the smallest image size possible.
We’ve seen a 10.5% decrease in load time and an 8% decrease on our start render after implementing image lazy loading on our home page. We’ve also observed a 15% decrease on requests made and a 25% decrease on the amount of bytes transferred.
Lazy loading is a good technique to reduce the amount of requests being fetched by our web pages. Placeholders play an important role on lazy loaded images in order to provide a better user experience. Many different implementations of placeholders exists and we can choose whichever implementation works with what we need for our websites.
Provided a small image we were able to calculate the correct placeholder size for the original image to be loaded minimizing flash or jitter that the users might see otherwise.