Blogroll

Lazy loading images

The other day I decided to show a random post from my images blog on my main moranjr.com page. The issue is that because of the number of images, the page was loading slowly so I wrote a lazy loader to the site a faster load even with the random posts.

What the script does is simply to load the images in the post but it only the displays those that are in the current view port.  By deferring some heavy image loads, your site will render much quicker if you have a lot of images to show.

There are other requirements too:

  • Make it as lean as possible
  • Have no JS library dependencies (jQuery or others)

The annotated code is below:

/* 	
	A lazy load script with no jQuery dependencies
	Script by Carlos Moran
	License MIT
*/

var ll = function(document, window, soffset, imgs){

	var i, 							// counter for DOM
	j; 							// counter for img data array 
	var imgsData = [];  		// Collect img src attributes in an array
	var innerHeight = window.innerHeight; // get view port dimensions

	if(imgs) {
		for(i=0; i < imgs.length; i++) {

			var pos = imgs[i].getBoundingClientRect();

			/* if image is visible already then exclude from images to load later */
			/* if its not loaded then save its position [i] in the imgs array, its vertical position, its load status and src attribute*/
			pos.top < innerHeight ? imgs[i].src = imgs[i].getAttribute("data-lsrc") : imgsData.push({
			i: i, y:pos.top, loaded: false, dsrc: imgs[i].getAttribute("data-lsrc")});

		}
	}

/* Call check elements on scroll - this will get the current top position and will set the src of the image to its proper value if it should be now in view */
	function checkElements(elems) {

		var offset = soffset || 0;

		/*elems refers to imgsData */
		for(j=0; j<elems.length; j++) {

			if(!elems[j].loaded && (elems[j].y < innerHeight+document.body.scrollTop+offset)) {
				imgs[elems[j].i].src = elems[j].dsrc;
				elems[j].loaded = true;
				console.log('Img '+ elems[j].i + ' loaded.');
			} 
		}

	}

	document.onscroll = function(){

			checkElements(imgsData);

	};
/* run the function once to load images that are initally in view - prior to any scrolling */
	checkElements(imgsData); 
/* when you call ll it will return the number of images that were processed by LLL */
	return {count: imgsData.length};

};

The usage of the script is below:

Call the ll function with window, document as is first two parameters and offset as its third parameter. I use offset to tell the image loader to load images early (before the image reaches the view port). The reason is simply so that the user doesn’t have to see that the images are loading just now. Some people (like Politico) use a jQuery ‘fade in’ to give the user a better impression.

The last parameter is the collection of images in the DOM with the data-lsrc attribute.  When you call ll it will look something like this:

var imgs = $("img[data-lsrc]");
lz = ll(document, window, 1000, imgs);

In my next post I will show you how I populated the data-lsrc attribute in WordPress+PHP and how I added the images to the colorbox to give them a nice lightbox effect when the user clicks on an image.

 


Show Comments