文章源自:http://viralpatel.net/blogs/lazy-load-image-wordpress-avatar-jquery/
Lazy Load Image & WordPress Gravatar using JavaScript / JQuery
Lazy Image Loading
After doing all these changes still if you have lots of images on your website, you might want to lazy load these images. Meaning load the image only when it is being viewed there by deferring http call until user is watching the image.
This technique can be very much useful in websites which display list of products with images. User can scroll through list and instead of loading all the product images while loading webpage, each image is loaded asynchronously when it comes in users viewport.
Now to achieve this we use simple JQuery snippet:
Step 1: Change <IMG> tag
First change the <img> tag for which you want to lazy load image to:
<!-- Before: --> <img src="http://foo/product.png" width="300px" height="200px" /> <!-- After: --> <img src="blank.gif" class="lazy" data-src="http://foo/product.png" width="300px" height="200px" />
Notice how we moved our image url from src
to data-src
attribute. Also we added blank.gif which is 1 px transparent gif file in src
attribute. We also added a CSS class lazy
to the image. This is to mark the image for lazy loading in jquery code which we will see shortly. Also do not forget to mention height
and width
attribute with <img>
tag. This make sure browser leave enough space around blank.gif to load original image.
Now on pageload, browser will load blank.gif file instead of product.png thus making http request more faster. If you have several images with src=blank.gif
, browser will load it just once and use it from cache.
Step 2: The JQuery Code Snippet
We want to load original image once that image is in browsers visible area. Following JQuery snippet do this task.
(function($) { var lazyloadImage = function(){ $('img.lazy').each(function(){ var distanceToTop = $(this).offset().top; var scroll = $(window).scrollTop(); var windowHeight = $(window).height(); var isVisible = distanceToTop - scroll < windowHeight; if (isVisible) { $(this).attr('src', $(this).attr('data-src')).removeClass('lazy'); } }); }; $(function(){ $(window).scroll(function() { lazyloadImage(); }); }); lazyloadImage(); })(jQuery);
In this snippet we hook a function to browsers scroll event. For each image that has lazy
css class on it, we iterate and see if the image is in visible area. If it is then we just copy value from image’s data-src
to its src
attribute. Once the image’s src attribute changes, browser will automatically load its content. Note how we remove lazy
class once the image is loaded to avoid further changes in DOM.
Further Optimization using data URI
The above image lazy loading technique reduce the page size significantly during the load time, but it still performs an http request on blank.gif. If somehow browser is not caching blank.gif image, then it will unnecessarily perform multiple http requests for it for each lazy image.
We can further optimize this by using Data URIs. It is a technique by which image data is directly embedded into document using some URI instead of linking external images within element or background-image in CSS.
The biggest reason why you want to do this is to save HTTP Requests.
Just change the <img>
tag we saw previously to:
<!-- Before: --> <img src="blank.gif" class="lazy" data-src="http://foo/product.png" width="300px" height="200px" /> <!-- After: --> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" class="lazy" data-src="http://foo/product.png" width="300px" height="200px" />
So intead of linking to external image blank.gif
, we embedded its content in src attribute of <img>
element using data URI. This will significantly reduces number of http requests in your webpage.
SEO Consideration
Lazy loading images would improve site speed significantly. But it also makes images less crawlable. Search engines like Google indexes the images from a website and display those in Image search. So if your website’s main source of traffic is image search than you may not want to implement this optimization technique.
But as I said earlier, there is always room for optimization. You can keep main images on your webpage as it is and make other less significant images to load dynamically. For example the Avatar images that you display in each comment. These images are not significant for indexing. A blog article can be showing 50 comments each with an Avatar image. Instead of loading 50 images during pageload, you can make them lazy by using our lazy code snippet.
I Don’t Want To Use JQuery
If you are not keen on using JQuery snippet as you might not using JQuery alltogether in your website! No worries. Following JavaScript code from Lorenzo Giuliani does exactly same thing.
/* lazyload.js (c) Lorenzo Giuliani * MIT License (http://www.opensource.org/licenses/mit-license.html) * * expects a list of: * `<img src="blank.gif" data-src="my_image.png" width="600" height="400" class="lazy">` */ !function(window){ var $q = function(q, res){ if (document.querySelectorAll) { res = document.querySelectorAll(q); } else { var d=document , a=d.styleSheets[0] || d.createStyleSheet(); a.addRule(q,'f:b'); for(var l=d.all,b=0,c=[],f=l.length;b<f;b++) l[b].currentStyle.f && c.push(l[b]); a.removeRule(0); res = c; } return res; } , addEventListener = function(evt, fn){ window.addEventListener ? this.addEventListener(evt, fn, false) : (window.attachEvent) ? this.attachEvent('on' + evt, fn) : this['on' + evt] = fn; } , _has = function(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } ; function loadImage (el, fn) { var img = new Image() , src = el.getAttribute('data-src'); img.onload = function() { if (!! el.parent) el.parent.replaceChild(img, el) else el.src = src; fn? fn() : null; } img.src = src; } function elementInViewport(el) { var rect = el.getBoundingClientRect() return ( rect.top >= 0 && rect.left >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight) ) } var images = new Array() , query = $q('img.lazy') , processScroll = function(){ for (var i = 0; i < images.length; i++) { if (elementInViewport(images[i])) { loadImage(images[i], function () { images.splice(i, i); }); } }; } ; // Array.prototype.slice.call is not callable under our lovely IE8 for (var i = 0; i < query.length; i++) { images.push(query[i]); }; processScroll(); addEventListener('scroll',processScroll); }(this);
ust add above JavaScript code in your site and you are good to go.