Search code examples
javascripthtmlcssjquery-masonrymasonry

Masonry + LazyLoad - Images Overlaying


I am using a base Mansory layout for building a basic image grid. Having to load hundreds or thousands of images from a database in the hope of building an infinite scroll page, I don't want the user to have to download all of them, mainly because of loading times but also because of all the wasted traffic that would mean (user shouldn't load image #500 unless he scrolls down until reaching it). To make this happen I tried to use the jQuery LazyLoad plugin.

This is how I fill my Masonry image grid:

            <ul class="grid effect-3" id="grid">
            <?php
            for ($i = 0; $i < count($thumbArray); $i++) {
                if ($i < 9) {
                    echo '<li><img class="img-grid" alt="' . $descArray[$i] . '" data-fullsize="' . $imgArray[$i] . '" src="' . $thumbArray[$i] . '"></li>';
                } else {
                    echo '<li><img class="img-grid lazy" alt="' . $descArray[$i] . '" data-fullsize="' . $imgArray[$i] . '" data-original="' . $thumbArray[$i] . '"></li>';
                }

            }
            ?>
        </ul>

Basically loading the first 9 images beforehand, and adding the 'lazy' CSS class to the others, as well as replacing the 'src' attribute with the Lazyload's 'data-original'.

(you might notice the 'alt' and 'data-fullsize' attributes, I am using them for a lightbox system and you can ignore them for the purposes of this question).

At the end of the index.php script I have:

<script src="js/jquery.lazyload.js"></script>
<script>$("img.lazy").lazyload();</script>

Importing the plugin and applying it to img tags with the class .lazy.

The problem lies in the fact that, I assume because of not knowing the height of the images, the Masonry grid system overlays any images that are loaded through the Lazyload process:

Broken overlapping images

As you can see, after the 9th image (when the lazyload specification starts), images start overlaying each other. I suppose this is because the image positions are dinamically calculated through Javascript since they all have position:absolute and top and left attributes set, but I am not sure.

Looking at the Masonry website, the first FAQ item is related to this and advises the use of imagesLoaded, which I have tried to do but with no success.

  • I have tried calculating the images' height through PHP's getimagesize() and setting it as a inline style attribute but it's too intense on the server and takes too long to load.
  • I have also tried adding items dinamically when the end of the page is reached (fetching db items through XHR would be an easy solution) but I wasn't successful - probably I would need to use Masonry's append function for this?

Bottom line is, I have been trying to find a solution for a few days now reading similar threads and implementing multiple solutions but to no avail. The Masonry grid system is indicated for my purposes because the image sizes may vary (e.g I don't want a gap after every vertical image), but I am really finding it troubling to couple it with Lazyload, and without it users will just experience much-more-than-necessary load times and the server will be under unnecessary stress.

Solutions for the images not overlaying please? Thanks in advance (y)


Solution

  • Most masonry plugins include a relayout method that you can call immediately after adding new items to force complete relayout of the items. In your case, you should only have to call .masonry('layout'); where "layout" is the name of your masonry instance. You will need to call this immediately after you add items to your grid. This should adjust all your image spacing for you. Also, you will want to use the addItems() method to add items as you scroll. If you try adding them manually, they will not be added to the Masonry array and you wont be able to apply layout to them.