Faster page loads with image lazy loading

Almost all traffic on slideshare goes to one type of page: the “view” page (the page where a document is displayed). As a result, we spend a lot of energy trying to tune the code that generates that page. Any decrease in page load time that we can get directly improves the user experience for all our users. Recently we were able to make big improvements by changing the way images load. This blog post will describe how we did it.

A large percentage of our page load time is taken up by images downloading. We’d already done a lot of work to reduce this (for example, by setting far-futures expires on many images, and by spriting images together to reduce the number of images downloaded). But the unique images for document thumbnails and profile pictures was not spritable, and far-future-expiry was unlikely to have much impact (since the images are usually unique to a given document). What to do?

After thinking about it a while, we realized that many of these profile and thumbnail images are below the fold in our current design, and therefore don’t need to be included in the initial pageload. Postponing loading of these images sped up the page a lot. By loading these images only when the user scrolls to those locations, we can avoid loading of these images unless the user is viewing them, saving a lot of bandwidth and speeding up the page quite a bit. This technique is called image lazyloading.

We implemented this on slideshare in february and noticed marked improvement in performance.
On one of our monitoring endpoints for a popular page

Average Size Images
Before Lazy load 497kb 1702
After Lazy load 445kb 942

On another of our endpoints for another page

Load Time Requests Bytes in
Before Lazy load 24.9s 123 2310kb
After Lazy load 13.2s 85 787kb

To implement lazy load, we have used the jQuery lazy load plugin.

So without much ado, here is the code.

<script type="text/javascript">
ss = <%= {:userPlaceholder => User::PLACEHOLDER_IMAGE}.to_json %>

<% comments.each do |comment| %>
 <li class="j-lazyload-comment comment">
   <span class="userSummary">
      <img src="<%= User::PLACEHOLDER_IMAGE %>" original-src="<%= comment.user.image %>"/>
      <%= comment.user.summary %>
   <span class="commentText"><%= h(comment.displayText) %>
<% end %>

The above section of the rails view generates the list of comments for the slideshow. Notice that we are populating the src attribute of the image tags with a placeholder image and setting a custom attribute ‘original-src’ with the actual image. This is resource url that the jQuery lazy load plugin will use.

And the javascript for the lazy load is

 $("li.j-lazyload-comment img").lazyload({
   effect: 'fadeIn', 
   placeholder: ss.userimage_placeholder

For the related slideshows section which has a list of thumbnails scrollable in a container, we use the following code

 $("li.j-lazyload-related img").lazyload({
   effect: 'fadeIn', 
   placeholder: ss.slideshow_placeholder, 
   container : '#relatedList'

As you see, it is quite easy to set up and get running. You could use the noscript tag to avoid lazyload and show the actual images for users who have javascript disabled. If you want more control over the behavior that what this plugin provides, you may be interested in waypoints.

I hope this post will help you make your website faster. Please let me know what you think of it in the comments section below. If making big web sites faster is the kind of thing you like doing, you should know that we’re hiring.

Jeba Singh Emmanuel
Senior Software Engineer

19 Responses to “Faster page loads with image lazy loading”

  1. Bedupako

    i am implimenting first thing in the morning in the website… thanks a lot! i didnt know of the jQuery thing

  2. Abhishek

    can you confirm that the images ACTUALLY load ‘lazily’. I think the images load as usual(as shown in the firebug NET console)

  3. Mariusz

    Very elegant implementation of lazy load. Your users (incl. me) are be very thankful for fast responsiveness of slideshare’s websites.
    (nb: see my presentation with many tips and tools for performance improvement )

    Would be very interested in some statistics of how this implementation imroved bounce rate and overall page views.
    @hiring: Working for you might be great.. but difficult from Europe ;)

    Thanks for sharing guys :)

  4. crmamx

    A lot of favorable comments from the “pros” on different forums. But what about us novices? Any chance you could be more detailed in how and where to install the different sections of code for us?


  5. Thomas Vervik

    On the homepage of the plugin there is a warning div:

    “Lazy Load is currently not usable. It does not work with the latest browsers as expected. I have currently no time updating the code myself. Patches are always welcome. If you find a solution just fork and send a pull request. Thanks!”

    I got a bit afraid using it with this warning, suddenly ending up after a lot of work with some code which doesnt work in all browser enviroments. Did you experience any trouble with it?

  6. Gaurish Sharma

    Hey Jeba,
    precise, accurate and to the point. Finally you are getting the audience that you might not have gotten at your blog. Good work buddy ;)

  7. Ankur Jain

    Came here through your newsletter. It’s the first time I heard of image lazy loading. I would be interested in answers for Nikhil’s and Thomas’ questions above.

  8. Jeba Singh Emmanuel

    @abhishek – Can you specify browser and OS versions? You need to set the src to the placeholder in your markup and set original-src to the image you want to lazy load. The newer browsers load the images immediately, so you should see the placeholders being loaded, not the actual images.
    @nikhil and @thomas – see reply to @abhishek, also

  9. Mike L

    Thanks for the article. Any word on how switching out the SRC affects Google Image search indexing? Really wonder how this affects SEO…

  10. Larry A

    Regarding your first code sample, I can only give you the advice to learn how to use taglibs and JSTL. Your Java scribbles make your code horribly hard to read and the approach goes against any idea of proper MVC-design. (What you are doing with your code is actually to merge model details straight into your view.)

    My second comment is regarding the jQuery lazy-load-plugin. It uses to the load function and other bits that are implemented differently in different browsers and which basically means non-existent cross-browser support (something which you can read in the very first and very red section of the plugin page).

    Anybody really thinking about cross-browser support should be VERY careful with your advice.

    Best regards,