4

I'm working on this website

The products on the center and right column are in a masonry container.

The problem I have is that If I apply the lazy load plugin to it, since it has different heights the images overlaps the others container:

enter image description here

This is how it looks (when not using lazy load):

enter image description here

Any ideas on how to make it work?

This is my script:

Posts.prototype.onBeforeRender = function() {
    var container;
    /* log("Msnry!"); */
    container = document.querySelector('#products_tmpl');
    App.msnry = new Masonry(this.el, {
        itemSelector: '.product',
        columnWidth: container.querySelector('.column-width'),
        gutter: container.querySelector('.gutter-sizer'),
        transitionDuration: '0.1s'
    });
    return delay(1000, this.reRenderLayout);
};

jQuery(function() {
    jQuery("img.lazy").lazyload({
        effect : "fadeIn"
    });
});

Post.prototype.returnImageForPost = function(maxSize) {
  var image_url, thumbnail_images;
  image_url = "";
  if (this.model.get("thumbnail_images") != null) {
    thumbnail_images = this.model.get("thumbnail_images");
    thumbnail_images = _.sortBy(thumbnail_images, function(item) {
      return -item.width;
    });
    _.each(thumbnail_images, function(thumb) {
      if (thumb.width >= maxSize) {
        return image_url = thumb;
      }
    });
  }
  return image_url;
};

This is the markup of each item:

<div class="product">
    <div class="image">
        <img class="lazy" data-original="<%= post_item.image_url.url %>">
    </div>
    <div class="obra_meta">
        <span class="nombre_artista"><%= item.title %></span>
        <span class="nombre_obra"><%= title %></span>
    </div>
</div>
  • is the height of containers fixed? then just apply `overflow:hidden` to these containers `.image { overflow:hidden; }` if thats a solution let me know to post it as answer – Sharky Aug 30 '14 at 09:44
  • No, is not fixed, each product has different image height and it should keep it that way –  Aug 30 '14 at 09:45
  • then add css `.image {float:left}` and at markup, after the `
    ` add a `
    ` be sure to refresh the cache of your browser so new css rules will apply.
    – Sharky Aug 30 '14 at 09:46
  • I have just done that. Look at the website. Still same problem. Images overlaps previous items text... –  Aug 30 '14 at 09:50
  • im seeing some nasty `position: absolute; left: 339px; top: 3439px;` on code. if the plugin calculates every div's position before load and then pushes the images in these `absolute` positions then its a pretty bad situation if you want variable height `img`. I may be wrong of course, but don't worry someone with more time available is going to help you :D – Sharky Aug 30 '14 at 09:54
  • 1
    Yeah, that `position` is made by the `masonry` plugin. That's why is not easy to use the `lazy load` on it as in other `static` position `div`. Let's see if someone can help me out :) –  Aug 30 '14 at 09:57
  • 1
    http://stackoverflow.com/questions/10096300/combining-lazyload-and-jquery-masonry – im_brian_d Sep 02 '14 at 05:54
  • Hey did ya'll ever get this to work? I'm having a similar problem. – David A. French Jun 16 '17 at 23:01

2 Answers2

3

You should probably recalculate the heights of the product-divs after images have been loaded. You can add a load parameter to your lazyload function, like so:

jQuery(function() {
    jQuery("img.lazy").lazyload({
        effect : "fadeIn",
        load : adjustHeights
    });
});

Since your product divs are absolute, you have to set their position yourself. The function to adjust heights should therefore be something like this:

function adjustHeights() {

    var columnheight1 = 10;
    var columnheight2 = 10;

    jQuery('.product').each(function(){
        //if product in left column
        itemheight = jQuery(this).height();
        if(jQuery(this).css('left') == '0px'){
            jQuery(this).css('top', columnheight1 + 'px');
            columnheight1 += itemheight + 30;
        }else{
        //if in right column
            jQuery(this).css('top', columnheight2 + 'px');
            columnheight2 += itemheight + 30;
        }

    });

    //don't forget to set post-container to the highest height
    if(Math.max(columnheight1, columnheight2) >0){
        jQuery('.products').css('height', Math.max(columnheight1, columnheight2) + 'px');
    }
}

It iterates through all your images and pushes them underneath the div that is above them in each column.

EDIT

As per this fiddle

klasske
  • 2,094
  • 1
  • 22
  • 29
  • Hi klasske. I tried your solution but I got `alert` with `0px` for some images and `339px` for others. And this was the result: http://imgur.com/06sMCdW all images overlapped :( –  Sep 01 '14 at 23:05
  • Ah, yeah I forgot to remove the alert. That's very strange. Was there no change in height for any of the products? – klasske Sep 02 '14 at 05:55
  • I meant, was there no change in the `top` value for any of the `product` divs? Not completely awake yet. – klasske Sep 02 '14 at 06:07
  • No, actually it removed the `top` value for all the products. So I got only `style="position: absolute; left: 0px` for every `.product`. That's why all are overlapped. –  Sep 02 '14 at 13:34
  • That's very strange. What if you use `offset` instead of directly setting `css`? I edited the code. – klasske Sep 02 '14 at 13:46
  • Thanks klasske. I have just updated it. It gets `top` value but first image disappears and the others overlaps the same as beginning issue. I see first image is at the top of the site. –  Sep 02 '14 at 13:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/60458/discussion-between-fxg-and-klasske). –  Sep 02 '14 at 13:56
  • @fxg I created a fiddle and figured out that it was a typo. After testing I also realized that you have a top and bottom margin for each product that I didn't take into account. Please try again with the edited code. – klasske Sep 02 '14 at 16:08
  • Works perfect! thank you very much for helping me out! –  Sep 02 '14 at 18:34
  • This sounds like the correct solution to a problem I'm having also. I'm very new to coding though and I'm having a little trouble following the solution. Could you break it down a little more @klasske ? Do you create a new adjustHeights function inside the lazy load frame work and then call it as an option using the load: adjustHeights ? Is that a correct understanding? – David A. French Jun 16 '17 at 23:04
0

Considering, that the best working for lazyload is when you know the image size (according to this: http://www.appelsiini.net/projects/lazyload ) , i would suggest to actually HAVE the image size.

You can get that before loading the images by PHP, check this: http://php.net/manual/en/function.getimagesize.php

Because i do not know the structure of post_item.image_url i assume you have possibility to add additional parameters to the object, in this case - height.

Then i would update the template for post_item object to also contains height (and width if needed), then i would update the template to:

<div class="product">
    <div class="image">
        <img class="lazy" data-original="<%= post_item.image_url.url %>" height="<%= post_item.image_url.height %>">
    </div>
    <div class="obra_meta">
        <span class="nombre_artista"><%= item.title %></span>
        <span class="nombre_obra"><%= title %></span>
    </div>
</div>

height is also W3C compliant for images: http://www.w3schools.com/tags/att_img_height.asp

Tooschee
  • 421
  • 3
  • 8
  • I have the updated the question with the `image_url` structure. –  Aug 30 '14 at 10:45
  • No, You didn't `Post.prototype.returnImageForPost` isn't responsible for images, from what i see it prepares thumbnails (if enabled) for posts. – Tooschee Aug 30 '14 at 11:30