Lazy Loading Images in Orchard
One thing I've been meaning to do forever is implement lazy loading for images. After all, if an image is below the fold, and the user never scrolls down the page, why waste bits downloading it?
While I was at it I also implemented a simple fade-in animation.
Requirements
This article assumes you're using Orchard 1.9 with the hiphouse swatch of the Cascade.Bootstrap theme, but the principles are simple and you can adapt it to pretty much any web page.
How It Works
Lazy loading is accomplished by a small amount of Javascript (shown below). As soon as document ready fires all images with a class of reveal
are stipped of their src
attribute, preventing them from displaying. The src url is saved to an attribute called data-src
so the image can be loaded correctly at the appropriate time.
The second phase is triggered by a load, resize
or scroll
event. In response to one of these events, including the initial load
event, all images that have not yet been revealed and have a data-src
attribute are tested to see if any part of the image is visible in the browser viewport. An image that is visible has a load event handler called fadeInImage
added to it that fades in the image by swapping the reveal
class for a reveal-fade-in
class. The reveal
class simply hides the image by making it transparent, and reveal-fade-in
animates an image fade-in.
How to Set an Image to be Lazy Loaded
So how do you set up an image so that it is lazy-loaded? Simply add the class reveal to it.
Javascript
Since jQuery is loaded for other reasons, the code takes advantage of it.
Here's the JS you'll need to include. If you're using the hiphouse swatch from Cascade.Bootstrap then it's already included in the custom.js
file.
$(document).ready(function () { // Immediately remove the src attribute from all images to be 'revealed' // if an image has already started loading it will be cancelled $('img.reveal').each(function () { var t = $(this); t.attr('data-src', t.attr('src')); t.removeAttr('src'); }); var fadeInImage = function (e) { e.stopPropagation(); e.data.removeClass('reveal').addClass('reveal-fade-in'); } // load and reveal images when they appear in the viewport var loadImage = function () { $('img[data-src].reveal').each(function () { if (isElementInViewport(this)) { var t = $(this); // fade-in the image after it has loaded t.one('load', t, fadeInImage); // load the image t.attr('src', t.attr('data-src')); t.removeAttr('data-src'); // only process this image once } }); } function isElementInViewport(el) { var rect = el.getBoundingClientRect(); return (rect.right >= 0 && rect.bottom >= 0 && rect.left <= (window.innerWidth || document.documentElement.clientWidth) && rect.top <= (window.innerHeight || document.documentElement.clientHeight)); } $(window).on('load resize scroll', loadImage); });
CSS
There are only two classes you need to support fade-in. These are already included in the hiphouse swatch in the Cascade.Bootstrap theme.
.reveal-fade-in { opacity: 1; -moz-transition: opacity linear 1s; -o-transition: opacity linear 1s; -webkit-transition: opacity linear 1s; transition: opacity linear 1s; } .reveal { opacity: 0; }
Sole comment