Jekyll Pagination and Infinite Scroll

Recently I updated the Scott Logic blog to implement infinite scrolling using a combination of Jekyll pagination and jScroll. Both of these components are quite fussy about their respective configuration, meaning that integrating them took longer than expected. I thought I’d share my solution in this blog post, hopefully saving others from the hours I spent digging into jScroll code or cursing Jekyll!

For a quick example integration I’ve created a demonstration site on with the sourcecode available on GitHub. You can see the rendered output below:

NOTE: The above iframe will no doubt render quite incorrectly on a mobile browser, so you might want to visit the example project’s generated site directly instead.

Pagination with Jekyll

In order to paginate the index page (index.html) of a Jekyll site all you have to do is add the paginate property to the sites configuration:

paginate: 10

This will cause the posts to be divided into pages and made accessible via the paginator object. Rendering the posts from a page is quite straightforward, rather than iterating over the contents of site.posts, instead iterate over paginator.posts:

{% for post in paginator.posts %}
<article>
<header>
<h2><a href="http://www.scottlogic.com"></a></h2>
<h5></h5>
<p></p>
</header>
</article>
{% endfor %}

Generating your site using the pagination option results in Jekyll creating multiple copies of the index page, each containing the posts for the given page. The first page, index.html resides in the usual location, whereas subsequent pages reside in numbered sub-folders starting at page2:

This slightly peculiar structure makes the next part a little more tricky …

The paginator object contains various other properties that can be used to render previous / next links to allow the user to navigate between the various pages. The following template can be used to render navigation links, notice the special casing for page #2 in order to navigate back to index.html, rather than page1/index.html, which does not exist!

<!-- render pagination links if there are more than one pages -->
{% if paginator.total_pages > 1 %}
<div class="pagination">
{% if paginator.previous_page %}
<!-- special case the second page to link back to index.html -->
{% if paginator.page == 2 %}
<a href="http://www.scottlogic.com/">&laquo; Prev</a>
{% else %}
<a href="http://www.scottlogic.com/page/">&laquo; Prev</a>
{% endif %}
{% else %}
<!-- if no 'previous' pages exit, render a span rather than an anchor -->
<span>&laquo; Prev</span>
{% endif %}

{% if paginator.next_page %}
<a class='next' href="http://www.scottlogic.com/page/">Next &raquo;</a>
{% else %}
<!-- if no 'next' pages exit, render a span rather than an anchor -->
<span class='next'>Next &raquo;</span>
{% endif %}
</div>
{% endif %}

With the above code in place you can support pagination with Jekyll. The next step is integration of jScroll to give infinite scrolling!

jScroll

jScroll is a jQuery plugin that works by magic, just add the following line of code to your site:

$('.content').jscroll()

And Hey Presto! Infinite scrolling (it’s SEO friendly too *rolls eyes*). Well, that’s the theory.

Unfortunately, in practice jScroll is very sensitive to the way in which you structure the page so that it can work its magic. If your configuration or structure isn’t correct, it fails silently and the only option is to delve into the code to find out what it expects.

Don’t get me wrong, I think jScroll is very neat. It’s simple and lightweight, but relies heavily on opaque conventions. In this post I’ll describe some of the inner-workings of jScroll and show how to make it play nicely with Jekyll.

The way jScroll works its magic is actually pretty simple. When you instantiate the jScroll plugin from a DOM element, it searches for the link that is used to navigate to the next page. It then adds a few structural div elements that it uses for content insertion and tracking scroll location. When the user scrolls to the bottom of the screen jScroll adds a loading indicator, and fetches the next page via an XHR request. The contents of the response are then added to the page.

A few things you need to ensure are:

  1. That the pagination links are within the DOM element used to construct jScroll. By default, it will search for the last anchor within this element and assume that the href attribute of this points to the next page. This is all a bit too ‘magic’ for my tastes, so I prefer to pass the nextSelector configuration option to jScroll, so that it can unambiguously locate the next link.
  2. jScroll hides the pagination controls when it is created. It assumes that the parent of the ‘next’ anchor element contains the pagination controls. As you can see in my template above, the div with class pagination is the direct parent of the next anchor, so this structure is fine.
  3. When jScroll fetches the next page, it will fetch an entire HTML page, e.g. page2/index.html. In order to update the current page it needs to identify the page fragment to extract and insert into the current page. This is achieved via the contentSelector configuration property.

As a result, the following jScroll configuration is suitable for paginating a Jekyll site:

$('.content').jscroll({
contentSelector: ".content",
nextSelector: '.next'
});

One other issue I found with jScroll is that when you reach the final page, it doesn’t hide the pagination links. I fixed that in a fork of jScroll, I’ll raise a pull request shortly :-)

Hopefully this blog post will help anyone else who is trying to integrate Jekyll and jScroll. When it works, it’s really rather neat!

Remember to pop over to GitHub to see a fully functioning example.

Regards, Colin E.

blog comments powered by Disqus