Combining LazyLoad and Jquery Masonry
Asked Answered
B

6

21

I have been trying to piece together masonry and moo tools lazyload however they both dont seem to go very well together although it possibly could just be because I am slightly useless at coding!

The masonry works on this page.

However when I try to put it together with lazyload it seems to totally mess up. Does anyone have any idea how to implement both plugins together?

I have spent 6 days trying to figure it out and this is my final hope ha!

Thanks

Brevity answered 10/4, 2012 at 20:52 Comment(4)
Could you do the same with a lazyload so I can see it messing up?Ns
Yes, I have just put lazy load in - it works in chrome, firefox it just totally messes up!Brevity
Ok so I have just noticed it seems to now work perfectly in chrome however the same weird effect happens in opera and firefox where it loads oddly!Brevity
Now I am the one who's facing this.. I have these features such as auto load more (when scroll is at bottom, lazy load image, and masonry layout. I use angular for this, and those features go to directives. None of the solutions work for me :(Cowry
G
31

Recently, I gotta solve this for one of my website. I have tried a couple of ways and it seems working.

1. First Method:

  • Load masonry on the items
  • Put a place holder on all images and use lazyload on them
  • Now, when each image fire lazyload.load callback, reload masonry -> a series of masonry('reload') [Updated jsfiddle with new images, easier to illustrate the point]

http://jsfiddle.net/7vEJM/8/

var $container = $('#container');
$container.imagesLoaded(function(){
    $container.masonry({
        itemSelector: '.item',
        columnWidth: function(containerWidth){
            return containerWidth / 12;
        }
    });
    $('.item img').addClass('not-loaded');
    $('.item img.not-loaded').lazyload({
        effect: 'fadeIn',
        load: function() {
            // Disable trigger on this image
            $(this).removeClass("not-loaded");
            $container.masonry('reload');
        }
    });
    $('.item img.not-loaded').trigger('scroll');
});

This method is good, but it has one disadvantage. The grid layout might not be kept the same since the time of masonry.reload() depends on each image's load time (i.e. the one supposed to be loaded first might only finish later)

2. Second Method: Look at sites like pinterest, i think, it does not follow the first method, because they have the container boxes arranged even before any image loaded, therefore, what I tried to achieve is to display just the boxes with same ratio as the images. The steps are:

  • Pass your images dimension (just return a json like {image1: [300,400],image2: [400,500]} )
  • Use CSS trick to make div box resize according to container. I found that trick here
  • Lazy load like normal, no need to trigger any reload since now, without the image, the boxes are alr arranged correctly

http://jsfiddle.net/nathando/s3KPn/4/

var $container = $('#container');
$container.imagesLoaded(function(){
    $container.masonry({
        itemSelector: '.item',
        columnWidth: function(containerWidth){
            return containerWidth / 12;
        }
    });
    $('.item img').lazyload({
        effect: 'fadeIn'
    });
    $('.item img').trigger('scroll');
});

[Edited to add the jsfiddle for the second method]

Notice:

  • In this fiddle, I manually put in the height/width ratio of each image in 'padding-bottom: xxx%' which should be passed in from your server code (refer to step 1)
  • Added in a border to make boxes visible
  • To illustrate that the boxes will be arranged even when the images not loaded, try uncomment /*display: none */ and comment display: block for #container.fluid .item img

Cheers

Gourd answered 3/5, 2013 at 15:51 Comment(4)
@Nathan_Do can you put a jsfiddle for thisOverblown
@adit: have added the new jsfiddle as requested but since i cannot replicate the server behaviour, kinda do that manually. Hope it still illustrates the point.Gourd
@NathanDo if I were had a pinterest card layout with comments, I'd have to calculate that div's height as well according to the comment?Pufahl
yes, i supposed so. You can just add in to the height of the image before deriving the ratio by using (height/width). It's similar, but not exactly how pinterest did it. They set the height of the div directly, not using %. They explained it in another post: #7109862. But I guess this will still be easier.Gourd
B
9

I posted the same answer on other same issues article. If you have the problem images get overlapped, I found the solution at the site below, although it is in Japanese.

http://www.webdesignleaves.com/wp/jquery/1340/

Hope this will help.

The point is use following;

$('img.lazy').load(function(){ ... })

HTML

<div id="works_list">
<div class="work_item">
<img class="lazy" src="images/dummy.gif" data-original="images/works/thumb/001.jpg" alt="">
<p>title 1</p>  
</div><!-- end of .work_item-->
<div class="work_item">
<img class="lazy" src="images/dummy.gif" data-original="images/works/thumb/002.jpg" alt="">
<p>title 2</p>  
</div><!-- end of .work_item-->
 ....
</div><!-- end of #works_list -->    

jQuery

$("img.lazy").lazyload({
    effect: 'fadeIn',
    effectspeed: 1000,
    threshold: 200
});

$('img.lazy').load(function() {
    masonry_update();
});

function masonry_update() {     
    var $works_list = $('#works_list');
    $works_list.imagesLoaded(function(){
        $works_list.masonry({
            itemSelector: '.work_item', 
            isFitWidth: true, 
            columnWidth: 160
        });
    });
 }    
Bookkeeper answered 4/1, 2015 at 20:6 Comment(1)
You saved my day :) Thanks alot!Marleenmarlen
C
5

softk5 answer wasn't working for me and causing freeze on the most of browser. Here is my following code and its working for me.

jQuery(document).ready(function(){
    jQuery("img.lazy").lazyload({
        effect: 'fadeIn',
        effectspeed: 1000,
        threshold: 200,
        load:function(){
            var $container = jQuery('.is_masonry');
            $container.masonry({
            }).imagesLoaded(function() {   $container.masonry();  });

        }
    });

});
Comradery answered 8/2, 2016 at 9:52 Comment(0)
G
3

The reason is that Masonry needs to know the dimensions of the image in order to lay out the items properly. However LazyLoad delays loading the image until the image is in the viewport, meaning that the image will have no dimensions (or have the dimensions of the dummy/placeholder image you set as the img src).

Gilkey answered 21/6, 2012 at 16:30 Comment(0)
R
0

maybe someone will have problems too, hope help.

to make it work with WordPress photoswipe-masonry theme is impossible without plugin modification.

next is related to this modification and just with masonry

a) lazyload use data-original="xxx" attribute to set image url . NOT src . to you need place some placeholder . may be 1x1 pixel that will be loaded without lazyload .

b) this placeholder needs to cover ALL space for future lazyloaded image, OR masonry will make all images visible as lazyloading view. it's because before images loaded it has zero size 0px x 0px . and all images fit in the visible area before loading. Lazyload count all as visible and load all.

to arrange ALL space for the future image you need a set

style="width:xxpx;height:xxpx;"

just width="xx" and height="xx" is not enough

so image placeholder became as :

<img src="http:..1x1px" data-original="http://real_image" style="width:xxpx;height:xxpx;">

then apply lazy load normal way and masonry. in any order.

Important - masonry update width to its column size, BUT not height, so if your column size = 50px, then you need to calculate heigh of placeholder

new_height = 50 / actual_width * actual_height;

so for WordPress theme need

$scaled_height =$options['thumbnail_width']/$full[1] * $full[2];

.....

<img src="http://xxxx/1x1px.jpg" data-original='. $thumb[0] .' itemprop="thumbnail" alt="'.$image_description.'" style="width:'.$full[1].'px;height:'.$scaled_height.'px;" width="'.$full[1].'" height="'.$full[2].'"/>

....

then add new lines below masonry init

var reloading = false;
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/jquery.lazyload/1.9.1/jquery.lazyload.min.js',function(){
  $('.msnry_item img').lazyload({
      effect: 'fadeIn',
      //container: container,
      threshold : 200,
      skip_invisible : false,
      failure_limit : 5,
      load: function() {
          if( ! reloading ) {
             reloading = true;
             setTimeout(function(){ 
                  container.masonry('reload');
                  reloading = false;
             }, 500);
         }
      }
  });
});
Ravelin answered 3/6, 2015 at 21:13 Comment(0)
P
0

Try to re-use "Masonry" in the "callback_loaded" of the LazyLoad

var ll = new LazyLoad({
    elements_selector: "img[data-src]",
    callback_loaded() {
        masonry = new Masonry(grid, {
            itemSelector: '.img-selector',
        });
    }
});

Further added code is below

callback_loaded() {
    masonry = new Masonry(grid, {
        itemSelector: '.img-selector',
    });
}
Pirozzo answered 3/9, 2019 at 11:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.