Note: iOS gives incorrect innerHeight and getBoundingClientRect values inside iframes, so that is why images are loaded immediately on it. CodePen forces iframes. That is evil.
Main purpose of lazy loading: save your bandwidth. Side effect: user's initial page load time might reduce. However user may also see images flashing as they are loaded.
How Lazy Loading Works
HTML syntax must not cause images to load (no img src=""), if image is in renderable DOM before script executes then browser will attempt to load it.
Traditional lazy loader syntax is like <img src="placeholder-image.png" data-src="actual-image-to-load.png" width="actualImagesWidth" height="actualImagesHeight" /> or some other form of HTML attribute hiding.
Downside of the above is that search engines and javascript disabled browsers won't see the real image. (However search engines have begun to execute JS so this is changing.)
Another downside is that you must have a separate placeholder image. You could also use inline base64 encoded image, but those are lengthy.
Lazy Loading Challenges
Should work JavaScript disabled
Just without lazy loading of course. Also means Google and other search engines can access the image.
Should have short syntax
Many solutions seem to easily become quite verbose with their HMTL. Especially if you want to support the above.
Don't be slow!
Some solutions seem to be very slow on initial page load: in my tests with mere 50 images jQuery JAIL plugin spent 150 ms setting stuff up!
Should account for both vertical and horizontal scrolling.
Some solutions only account for vertical scrolling.
Should be possible to make work on Internet Explorer 8-
The smaller you make it and the more feature requirements you add the more likely you are going to run into compatibility barriers.
Image that fails to load:
The Requirements
With IE8 support:
IE8 will not lazy load! Conditional comments are required for IE8 to display the images.
Add before image: <!--[if IE 9]><!--><noscript data-lazy-img><!--<![endif]-->
Add after image: <!--[if IE 9]><!--></noscript><!--<![endif]-->
Image must have width and height attributes set (as always with lazy loading).
IE9+:
Add before image: <noscript data-lazy-img>
Add after image: </noscript>
Image must have width and height attributes set (as always with lazy loading).
Customization
noscriptImageLazyLoader can take a few options in:
Array of events after which images visible in viewport are checked for. Note that mobile devices such as iOS do not update their scroll position information in real time when touch scrolling.
interval
A fallback mechanism that checks every 0.5 seconds for images visible in viewport by default. Can be turned off by giving zero or any non-number.
placeholder
Placeholder image. Defaults to transparent base64 encoded gif image (which allows you to set a loading image as background image in CSS).
The Good
Shortest syntax I know of that also supports JS disabled.
Answers all the challenges in a positive manner.
The Bad
There can be a small delay after page is first rendered and JavaScript execution which means page layout might be re-calculated when noscript elements are replaced with images.
Also doesn't support responsive loading if you fancy that.
The Weird & Ugly
Internet Explorer Conditional Comments: IE 8 and below don't allow accessing contents of noscript elements.
With some simple conditional comments we can hide noscript element tags from those IEs so they work as if JS is disabled.