51

As many of you know it is widely used to lazy load images.

Now i want to use this as lazy load div background images.

How can i do that ?

I am currently able to use http://www.appelsiini.net/projects/lazyload that plugin

So i need to modify it in a way that it will work with div backgrounds

Need help. Thank you.

The below part i suppose lazy loads images

$self.one("appear", function() {
    if (!this.loaded) {
        if (settings.appear) {
            var elements_left = elements.length;
            settings.appear.call(self, elements_left, settings);
        }
        $("<img />")
            .bind("load", function() {
                $self
                    .hide()
                    .attr("src", $self.data(settings.data_attribute))
                    [settings.effect](settings.effect_speed);
                self.loaded = true;

                /* Remove image from array so it is not looped next time. */
                var temp = $.grep(elements, function(element) {
                    return !element.loaded;
                });
                elements = $(temp);

                if (settings.load) {
                    var elements_left = elements.length;
                    settings.load.call(self, elements_left, settings);
                }
            })
            .attr("src", $self.data(settings.data_attribute));
    }
});

Jquery plugin lazy load

Barlas Apaydin
  • 6,794
  • 10
  • 50
  • 81
MonsterMMORPG
  • 20,310
  • 69
  • 183
  • 306

10 Answers10

28

First you need to think off when you want to swap. For example you could switch everytime when its a div tag thats loaded. In my example i just used a extra data field "background" and whenever its set the image is applied as a background image.

Then you just have to load the Data with the created image tag. And not overwrite the img tag instead apply a css background image.

Here is a example of the code change:

if (settings.appear) {
    var elements_left = elements.length;
    settings.appear.call(self, elements_left, settings);
}
var loadImgUri;
if($self.data("background"))
    loadImgUri = $self.data("background");
else
    loadImgUri  = $self.data(settings.data_attribute);

$("<img />")
    .bind("load", function() {
        $self
            .hide();
        if($self.data("background")){
            $self.css('backgroundImage', 'url('+$self.data("background")+')');
        }else
            $self.attr("src", $self.data(settings.data_attribute))

        $self[settings.effect](settings.effect_speed);

        self.loaded = true;

        /* Remove image from array so it is not looped next time. */
        var temp = $.grep(elements, function(element) {
            return !element.loaded;
        });
        elements = $(temp);

        if (settings.load) {
            var elements_left = elements.length;
            settings.load.call(self, elements_left, settings);
        }
    })
    .attr("src", loadImgUri );
}

the loading stays the same

$("#divToLoad").lazyload();

and in this example you need to modify the html code like this:

<div data-background="http://apod.nasa.gov/apod/image/9712/orionfull_jcc_big.jpg" id="divToLoad" />​

but it would also work if you change the switch to div tags and then you you could work with the "data-original" attribute.

Here's an fiddle example: http://jsfiddle.net/dtm3k/1/

fehrlich
  • 2,263
  • 2
  • 24
  • 41
  • 1
    Just wanted to point out that the JS in that fiddle has a number of instances where the custom selectors functions are being called with the wrong names. Stuff like: "rightoffold" should be "rightofscreen." Here is an updated fiddle where all the selector extension function names and calls have been corrected: http://jsfiddle.net/dtm3k/93/ – ORyan Apr 17 '13 at 09:53
23

I do it like this:

<div class="lazyload" style="width: 1000px; height: 600px" data-src="%s">
    <img class="spinner" src="spinner.gif"/>
</div>

and load with

$(window).load(function(){

    $('.lazyload').each(function() {

        var lazy = $(this);
        var src = lazy.attr('data-src');

        $('<img>').attr('src', src).load(function(){
            lazy.find('img.spinner').remove();
            lazy.css('background-image', 'url("'+src+'")');
        });

    });

});
maosmurf
  • 1,574
  • 14
  • 14
  • And where do you call $.lazyload()? – Pherrymason Mar 24 '14 at 16:53
  • 1
    I don't call it myself, but register a callback using $(window).load() see also https://api.jquery.com/load-event/#entry-examples – maosmurf Mar 24 '14 at 20:20
  • I can't see how this lazy loads the images in the page, if `src` attribute of images are not populated on page load, `$(window).load` will fire and then all your images will be loaded at once... – Pherrymason Mar 25 '14 at 08:28
  • whole page, thus all elements except the images, loads. all text available, JS loaded and interpreted. only then images ae loaded, as per data-src. your browser has a limit of connections per host, so you wont load all images at once – maosmurf Mar 27 '14 at 00:35
  • I don't think that's the same behaviour lazyload plugin is offering. The lazyload plugin loads the images only when they are being about to be visible, for example, when you scroll down where those images are placed. This way if there are images not being displayed, they are not loaded. Even if browsers have a limit of connections per host, they all are going to be loaded and that's not lazy load. – Pherrymason Mar 27 '14 at 10:42
8

I've found this on the plugin's official site:

<div class="lazy" data-original="img/bmw_m1_hood.jpg" style="background-image: url('img/grey.gif'); width: 765px; height: 574px;"></div>

$("div.lazy").lazyload({
      effect : "fadeIn"
});

Source: http://www.appelsiini.net/projects/lazyload/enabled_background.html

Barlas Apaydin
  • 6,794
  • 10
  • 50
  • 81
5

I've created a "lazy load" plugin which might help. Here is the a possible way to get the job done with it in your case:

$('img').lazyloadanything({
    'onLoad': function(e, LLobj) {
        var $img = LLobj.$element;
        var src = $img.attr('data-src');
        $img.css('background-image', 'url("'+src+'")');
    }
});

It is simple like maosmurf's example but still gives you the "lazy load" functionality of event firing when the element comes into view.

https://github.com/shrimpwagon/jquery-lazyloadanything

shrimpwagon
  • 690
  • 10
  • 21
2

It's been a moment that this question is asked, but this doesn't mean that we can't share other answers in 2020. Here is an awesome plugin with jquery:jQuery Lazy

The basic usage of Lazy:

HTML

<!-- load background images of other element types -->
<div class="lazy" data-src="path/to/image.jpg"></div>
enter code here

JS

 $('.lazy').Lazy({
    // your configuration goes here
    scrollDirection: 'vertical',
    effect: 'fadeIn',
    visibleOnly: true,
    onError: function(element) {
        console.log('error loading ' + element.data('src'));
    }
});

and your background images are lazy loading. That's all!

To see real examples and more details check this link lazy-doc.

Houssem ZITOUN
  • 451
  • 1
  • 4
  • 19
1

I had to deal with this for my responsive website. I have many different backgrounds for the same elements to deal with different screen widths. My solution is very simple, keep all your images scoped to a css selector, like "zoinked".

The logic:

If user scrolls, then load in styles with background images associated with them. Done!

Here's what I wrote in a library I call "zoinked" I dunno why. It just happened ok?

(function(window, document, undefined) {   var Z = function() {
    this.hasScrolled = false;

    if (window.addEventListener) {
      window.addEventListener("scroll", this, false);
    } else {
      this.load();
    }   };
     Z.prototype.handleEvent = function(e) {
    if ($(window).scrollTop() > 2) {
      this.hasScrolled = true;
      window.removeEventListener("scroll", this);
      this.load();
    }   };
     Z.prototype.load = function() {
    $(document.body).addClass("zoinked");   };
     window.Zoink = Z; 
})(window, document);

For the CSS I'll have all my styles like this:

.zoinked #graphic {background-image: url(large.jpg);}

@media(max-width: 480px) {.zoinked #graphic {background-image: url(small.jpg);}}

My technique with this is to load all the images after the top ones as soon as the user starts to scroll. If you wanted more control you could make the "zoinking" more intelligent.

Alex Grande
  • 7,405
  • 1
  • 24
  • 28
1

Lazy loading images using above mentioned plugins uses conventional way of attaching listener to scroll events or by making use of setInterval and is highly non-performant as each call to getBoundingClientRect() forces the browser to re-layout the entire page and will introduce considerable jank to your website.

Use Lozad.js (just 569 bytes with no dependencies), which uses InteractionObserver to lazy load images performantly.

Apoorv Saxena
  • 3,736
  • 9
  • 27
  • 44
  • Good option but currently a fallback to old algorithms should be provided because of not all major browsers support this API. – Alexander Pravdin Jun 20 '18 at 02:41
  • Polyfill for IntersectionObserver can be loaded dynamically as per need in case browser support isn't available https://www.npmjs.com/package/intersection-observer – Apoorv Saxena Nov 02 '18 at 07:47
1

Mid last year 2020 web.dev posted an article that shared some new ways to do this with the the new IntersectionObserver which at the time of writing this answer is supported in all major browsers. This will allow you to use a very light weight background image, or background color placeholder while you wait for the image to come to the edge of the viewport and then it is loaded.

CSS

.lazy-background {
  background-image: url("hero-placeholder.jpg"); /* Placeholder image */
}

.lazy-background.visible {
  background-image: url("hero.jpg"); /* The final image */
}

Javascript

document.addEventListener("DOMContentLoaded", function() {
  var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));

  if ("IntersectionObserver" in window) {
    let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          entry.target.classList.add("visible");
          lazyBackgroundObserver.unobserve(entry.target);
        }
      });
    });

    lazyBackgrounds.forEach(function(lazyBackground) {
      lazyBackgroundObserver.observe(lazyBackground);
    });
  }
});
zmanc
  • 4,551
  • 12
  • 41
  • 82
0

I know it's not related to the image load but here what I did in one of the job interview test.

HTML

<div id="news-feed">Scroll to see News (Newest First)</div>

CSS

article {
   margin-top: 500px;
   opacity: 0;
   border: 2px solid #864488;
   padding: 5px 10px 10px 5px;
   background-image: -webkit-gradient(
   linear,
   left top,
   left bottom,
   color-stop(0, #DCD3E8),
   color-stop(1, #BCA3CC)
   );
   background-image: -o-linear-gradient(bottom, #DCD3E8 0%, #BCA3CC 100%);
   background-image: -moz-linear-gradient(bottom, #DCD3E8 0%, #BCA3CC 100%);
   background-image: -webkit-linear-gradient(bottom, #DCD3E8 0%, #BCA3CC 100%);
   background-image: -ms-linear-gradient(bottom, #DCD3E8 0%, #BCA3CC 100%);
   background-image: linear-gradient(to bottom, #DCD3E8 0%, #BCA3CC 100%);
   color: gray;
   font-family: arial;    
}

article h4 {
   font-family: "Times New Roman";
   margin: 5px 1px;
}

.main-news {
   border: 5px double gray;
   padding: 15px;
}

JavaScript

var newsData,
    SortData = '',
    i = 1;

$.getJSON("http://www.stellarbiotechnologies.com/media/press-releases/json", function(data) {

   newsData = data.news;

   function SortByDate(x,y) {
     return ((x.published == y.published) ? 0 : ((x.published < y.published) ? 1 : -1 ));
   }

   var sortedNewsData = newsData.sort(SortByDate);

   $.each( sortedNewsData, function( key, val ) {
     SortData += '<article id="article' + i + '"><h4>Published on: ' + val.published + '</h4><div  class="main-news">' + val.title + '</div></article>';
     i++;    
   });

   $('#news-feed').append(SortData);
});

$(window).scroll(function() {

   var $window = $(window),
       wH = $window.height(),
       wS = $window.scrollTop() + 1

   for (var j=0; j<$('article').length;j++) {
      var eT = $('#article' + j ).offset().top,
          eH = $('#article' + j ).outerHeight();

          if (wS > ((eT + eH) - (wH))) {
             $('#article' + j ).animate({'opacity': '1'}, 500);
          }
    }

});

I am sorting the data by Date and then doing lazy load on window scroll function.

I hope it helps :)

Demo

Bhaumik Mehta
  • 309
  • 2
  • 4
  • 3
    This isn't lazy loading, you are returning all data from the server and then just setting the visibility of the item when scrolling down. Lazy loading is requesting data from the server as the user scrolls towards the content. If you got away with this in interview then well done. – donners45 Nov 08 '16 at 16:22
0

Using jQuery I could load image with the check on it's existence. Added src to a plane base64 hash string with original image height width and then replaced it with the required url.

$('[data-src]').each(function() {
  var $image_place_holder_element = $(this);
  var image_url = $(this).data('src');
  $("<div class='hidden-class' />").load(image_url, function(response, status, xhr) {
    if (!(status == "error")) {
      $image_place_holder_element.removeClass('image-placeholder');
      $image_place_holder_element.attr('src', image_url);
    }
  }).remove();
});

Of course I used and modified few stack answers. Hope it helps someone.

Vishal Kumar Sahu
  • 887
  • 3
  • 13
  • 25