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.
        

Noscript Image Lazy Loader (vanilla JavaScript version)

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

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:

{
    attribute: 'lazy-img',
    events: ['resize', 'scroll', 'touchend'],
    interval: 500,
    placeholder: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
}
        
attribute
Defaults to <noscript data-lazy-img>
events
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.

But then we get no lazy loading.