Jack Barber / Website Design

Masonry and Infinitescroll with Perch CMS

Masonry and Infinitescroll with Perch CMS

Over the last couple of weeks I've been putting a simple site together for a friend. Julie-Ann Smith is a pattern designer - she wanted a really simple site to showcase here designs and start to build her online presence.

The site is built with Perch which makes it really easy for Jules to update the site herself, adding new blog posts and editing content as often as she likes.

While the site is very simple, there was one bit of functionality Jules requested which I hadn't implemented with Perch before - Masonry and Infinitescroll.

Masonry

Masonry is a widely-used Javascript library for making blocks of content tile neatly together, regardless of their size and shape. Basically it creates a Pintrest style layout which can be applied to any type of content.

Infinitescroll

Infinitescroll is another widely used Javascript plugin which prevents the need for a user to click 'next' at the bottom of a page (of news, for instance). Rather, the browser fetches the next page of content and appends it to the bottom of the existing page.

This is a really nice UI feature (provided your users don't need to reach the footer of your page), and works particularly well for graphic based websites like Jules'.

Perch Feathers

Perch is amazing. Both from a user perspective and from a development point of view. They provide a number of 'feathers' to help get projects started - including both Masonry and Infinitescroll.

Perch Feathers are like discrete packages of code which when added to a website take out all the hassle of finding a particular plugin, loading jQuery or other dependencies and so on - they just work.

Getting them Working Together

Out of the box both of these plugins did what I wanted. However, I found that when loading the 'next' page, the elements were positioned at the top of the existing page, and obscurred by the original content. Not ideal.

This is due to Masonry using 'absolute' positioning on each element, and not being triggered to re-organised the page when the new content was added to the page.

To get around this I made use of the callback function built into Inifinitescroll to tidy up the page by appending the newly loaded content to the end of the page and triggering Masonry to re-arrange the page accordingly.

Perch Feathers provide configuration files (where appropriate) into which any customisation can be added. Here are mine, showing what is required to get this working...

Masonry:

/perch/addons/feathers/masonry/js/perch.masonry.js

Code:

$(document).ready(function() {
    var width = $(window).width();
    var $container = $('.cms_masonry_container');
    $container.imagesLoaded(function(){
        // Different configurations for different breakpoints:                    
        if(width>'768'){
            $container.masonry({
                itemSelector : '.cms_masonry_item',
                columnWidth: function( containerWidth ) {
                    return containerWidth / 4;
                  }
            });
        }else if(width>'480'){
            $container.masonry({
                itemSelector : '.cms_masonry_item',
                columnWidth: function( containerWidth ) {
                    return containerWidth / 2;
                  }
            });
        }else{
            $container.masonry({
                itemSelector : '.cms_masonry_item',
                columnWidth: function( containerWidth ) {
                    return containerWidth / 1;
                  }
            });
        }
    });
});

Infinitescroll:

/perch/addons/feathers/infinitescroll/js/perch.scrolling.js

Code:

$(document).ready(function() {
    $container = $('.cms_masonry_container');
    $('.cms_scroll_container').infinitescroll({
        navSelector  : ".paging",
        nextSelector : ".paging a.cms_next",
        itemSelector : ".cms_scroll_container .cms_scroll_post",
        loading: {
            finishedMsg: 'No more pages to load.'
        }
    }, function(newElements){
            // Callback function:
            var $newElems = $( newElements ).css({ opacity: 0 });
            $newElems.imagesLoaded(function(){
                $newElems.animate({ opacity: 1 });
                $container.masonry( 'appended', $newElems, true );
            });
    });
});

HTML and CSS

In order to fetch the new content, the Perch Infinitescroll Feather makes use of certain classes, applied to different elements on the page. These determine the container, the item and the link which targets the next page.

I had no reason to change these from the defaults, as outlined in the Perch documentation, so I simply amended my blog template as follows:

/perch/templates/blog/post_in_list.html
<perch:before>
<ul class="hfeed listing cms_scroll_container cms_masonry_container">
</perch:before>
    <li class="hentry cms_scroll_post cms_masonry_item">
        // Put your post content here
    </li>
<perch:after>
    </ul>
    <perch:if exists="paging">
        <div class="paging">
            <perch:if exists="not_first_page">
                <a href="<perch:blog id="prev_url" encode="false" />">Previous</a>
            </perch:if>
            <perch:if exists="not_last_page">
                <a href="<perch:blog id="next_url" encode="false" />" class="cms_next">Next</a>
            </perch:if>
        </div>
    </perch:if>
</perch:after>

This is the post_in_list.html template in it's simplest form - you'll need to add some more Perch tags to get it to display titles, excerpts, images etc.


Simple but Effective

This is a simple but effective solultion to getting Infinitescroll and Masonry playing nicely together with a Perch blog. I will be implementing something similar on a new section of my own site soon - stay tuned for that!

As always, please get in touch if you spot an issue with my code, or want more help getting this running on your own site.