Improved Lazy Loading for mobile devices (iPhone, Android) with Lazy Load 1.7

The latest version of the jQuery Lazy Load plugin (released Jan 29th, 2012) included the ability to customize your data attribute parameter. This is a pretty helpful update; I realized it could be used to set multiple source images for the same node. Here's how you can use it to optimize images, cutting down on data transfer for mobile devices.

Set up your lazy loading the normal way - generally this is gives you HTML like this:

<img src="img/ajax-loader.gif" data-original="img/800.jpg" width="810" height="800" alt="A cute kitten">

The data-original attribute specifies the actual source of your lazy load image. The javascript to complement then looks something like this:

$('img')
  .lazyload({
    effect : 'fadeIn'
  });

Now your lazy loading should be working, if your scripts are included in your page and everything is set up correctly. However, if your site features very large images and you have a responsive stylesheet set up, your readers can benefit from loading optimized images. I like to give a "width-full" class to any images that are full-width optimized. Then I hit that class in my media queries, hiding any .width-full content with display:none;. Because the lazy load script doesn't load hidden images by default, this prevents the script from loading on those images, saving readers the download time.

Now go back to your image tags, and specify the location for the optimized image in a data-mobile attribute. Something like this:

<img src="img/ajax-loader.gif" data-original="img/800.jpg" data-mobile="img/100.jpg" class="width-full" width="810" height="800" alt="A cute kitten">

You can add these changes to your template files when appropriate, so this is all done under the hood.

As it is, your lazy load should still be working the default way in all circumstances. A media query is how we will trigger something different to happen for mobile. With just a few lines of CSS:

@media only screen
and (max-width: 480px) {
  .width-full {
    display:none;
  }
}

Now we add a few lines of jQuery to call out those images. We aren't targeting the class, we're targeting the visibility and the attribute. We only want the lazy load plugin to run the mobile version when the media query rules have hidden it, and only then if it has mobile optimized content. So after our initial lazy load, you can add this:

$('img:hidden[data-mobile]')
  .attr('width','')
  .attr('height','')
  .show()
  .lazyload({
    effect : 'fadeIn',
    data_attribute : 'mobile'
  });

There's a few things going on here. First it resets the image height and width attributes so that your image loads without being distorted, then it shows the image, and runs the lazyload directly, using the data-mobile data_attribute parameter. If there's no mobile-optimized version, it will just keep the image hidden. You can cut down load times while making your content available in the right context.


Hi Erin,

thx a lot for your nice idea. Brilliant. Nonetheless there is one important thing to be aware of related to the goal of saving bandwidth.

While

$('img') ...

followed by

$('img:hidden[data-mobile]') ...

does a good job of showing the proper target image, it does not prevent that both image sources are downloaded.

Changing the first object selector to

$('img:not(:hidden)')

solves this.

greets
Olaf

Hey Olaf, thanks for the kind words.

I didn't bother with a :visible or .not(:hidden) pseudo-selector because the plugin has that option built-in with a default "skip_invisible" param. It isn't mentioned on the blog post, but it is visible in the source. Does that cover what you're talking about?

Thanks, I appreciate the feedback!


Hi Erin,

maybe it has something to do with my enviroment, but the default plugin settings (e.g. skip all hidden images, i left this untouched) does not prevent the download of the "data-original" source on a image that was set to hidden. At least with latest webkit and gecko browsers and my case.

On a dev page the header visual (the big picture) is handle through lazyload. There are two data image sources. If the browser viewport is below 480px (on init), it triggers the small image source ('figure-one-480.jpg'). Otherwise it delivers the big picture ('figure-one.jpg').

A ".mobilesrc' css class sets the image state to hidden (display: none;) within a appropriate media query.

Example 1 (loading the appropriate source only):
http://files.creatics.de/tests/schreyl/index.html

In my enviroment all images to handle through lazyload has a trigger class (.load), so in this case the first declaration looks like

$('img.load:not(:hidden)')
... calling lazyload plugin

and afterwards

$('img:hidden[data-mobile]')
... calling lazyload plugin with different data_attribute

Example 2 (both sources are loaded):
http://files.creatics.de/tests/schreyl/index2.html

$('img.load')
.lazyload({
	effect : 'fadeIn'
});

and again afterwards

$('img:hidden[data-mobile]')
... calling lazyload plugin with different data_attribute

greets
Olaf

About the Author

Erin Nunn, Project Manager

Equal parts structure and creativity, Erin is a project manager and UX designer with a great attitude and knack for translating big goals into digestible pieces. Through various roles, Erin has led the development of mobile apps, responsive websites, nonprofit databases, complex web applications, and Fortune 500 websites. She excels at understanding needs, wireframing/prototyping, creating actionable plans, identifying the latest technology and time-saving tools, ensuring quality, and exceeding expectations.

Fueled by doses of sugar, cups of chai and time with her incredible family, Erin geeks out on simple things like markers, books, traveling, grocery stores, excessive laughter, and going fast.

Interested? Let's talk.