The Interaction Design Pattern

September 25th, 2008

Infinite scroll has been called autopagerize, unpaginate, endless pages. But essentially it is pre-fetching content from a subsequent page and adding it directly to the user’s current page.

Problem Summary:

User is browsing paged content.

Use When:

  • Retaining the user is important and clicking “Next Page” is a usability barrier.
  • The full content available is too large to show on initial load.
  • The content is available in paged chunks: search results, blog posts, product listings portfolio features.

Advantages:

  • Users are retained on the site far better.
    • Users are less likely to continue on to the next “page” if they have to click something versus it being delivered automatically to them. [citation needed]
  • Requires no adjustment in a user’s typical reading habits.
  • The added functionality needs no affordances or instruction.
  • As long as the functionality is enhancing an existing navigational structure (like the wordpress plugin here), it remains SEO-friendly and Accessible. It will degrade gracefully if a user does not have JavaScript enabled..

Disadvantages:

  • The “footer” of the page will be typically impossible to reach.
  • Currently there is no way to cancel or opt-out of the behavior.
  • There is no permalink to a given state of the page.
  • Dynamically adding more content to the page increases the memory footprint of the browser. Depending on the browser, this could account for around 50megs of RAM.
  • Analytics will not immediately capture the event, so custom configuration is required.
  • FOR GOD’S SAKE, DON’T BREAK THE BACK BUTTON.

Implementation Recommendations:

  • Depending on site latency, new content can be fetched aggressively (when a user has 500px of the page left to scroll) versus at the last moment (with ~100px left).
  • User should be notified when there is no more content available.
  • Consider a faux pagination widget to allow for navigation within the new content. Travis Isaacs has ideas on a running pagination.
  • Infinite scroll should be implemented as progressive enhancement. Typical navigation/pagination should be present for users with javascript disabled. Javascript-enabled users, however, will experience the more rich reading functionality.

Examples in the wild:

    WordPress Plugin Installation

    June 30th, 2008
    1. Download the plugin.
    2. Install it to your /wp-content/plugins/ directory
    3. Activate the plugin in your WordPress Admin UI.
    4. Visit the Settings / Infinite Scroll page to set up the css selectors.
    5. The plugin will now work for a logged in Admin, but will be disabled for all other users; you can change this.

    CSS Selector Setup

    You need configure the plugin with CSS selectors that match your theme.

    Content CSS Selector
    The DIV that wraps around all posts. New posts will be inserted at the bottom of this DIV.
    Post CSS Selector
    The selector that selects all posts on a page. Each post must be surrounded by a single DIV.
    Navigation links CSS Selector
    This DIV contains the Next Posts and Previous Posts link.
    Previous Posts CSS Selector
    This A tag is what points to the 2nd page of posts.

    Troubleshooting

    • Your posts need to be wrapped in divs all next to each other.
    • You need a link on your page to the next page of posts.

    FAQ

    Can I change the number of posts loaded?
    Yup. But that’s a WordPress thing. Go to Settings / Reading
    Is it SEO-Friendly?
    Yes all enhancements are made via javascript only, so search spiders see no difference.
    Is it accessible?
    Things won’t change for screen-readers. This technique degrades gracefully.
    Why doesn’t it work on ____ page?
    Currently, the plugin is disabled for everything but the main page, but I’ll work on enabling it for Archives, Categories, and Tags.
    Does it still keep going, even at the end of the blog?
    Infinite scroll is configured to die when it hits a 404 Not Found status code, so when it goes through all your archives it should hit a /page/43/ (or something) that doesn’t exist, then show a message “Congrats, you’ve reached the end of the internet.” Some wordpress themes don’t report not found pages with a 404. Try a different theme or contacting the theme author.
    Do I need to edit my theme to make this work?
    Probably not, nope.
    Will this do form posts for get new data?
    Nope?
    You mean it just works?
    Yup.
    Really?
    I hope so. But due to the infinitudes of wordpress installations, each case is different. Different themes and other plugins may break infinite scroll’s functionality.

    Customization

    This information will probably help styling.

    • <div id="infscr-page-2" class="infscr-pages"> will contain the page 2 content, etc
    • <div id="infscr-loading"> is the loading div.

    Infinite Scroll jQuery Plugin

    June 29th, 2008

    Note: This documentation is currently out-of-date and will be updated soon. In the mean time, please refer to the GitHub README and Wiki.

    This plugin aims to progressively enhance your page. Your navigation/pagination elements should be present in the HTML for non-js users, but the plugin will utilize those links to build out a more rich browsing experience.

    Download the jQuery plugin

    Version 1.5.100504
    jquery.infinitescroll.js and minified are now on GitHub

    Usage

    Minimum required configuration

    This is the minimum amount of configuration you can do, if you want things to work:

    // infinitescroll() is called on the element that surrounds 
    // the items you will be loading more of
      $('#content').infinitescroll({
     
        navSelector  : "div.navigation",            
                       // selector for the paged navigation (it will be hidden)
        nextSelector : "div.navigation a:first",    
                       // selector for the NEXT link (to page 2)
        itemSelector : "#content div.post"          
                       // selector for all items you'll retrieve
      });

    All options

    // usage:
    // $(elem).infinitescroll(options,[callback]);
     
    // infinitescroll() is called on the element that surrounds 
    // the items you will be loading more of
    $('#content').infinitescroll({
     
      navSelector  : "div.navigation",            
                     // selector for the paged navigation (it will be hidden)
     
      nextSelector : "div.navigation a:first",    
                     // selector for the NEXT link (to page 2)
     
      itemSelector : "#content div.post",          
                     // selector for all items you'll retrieve
     
      debug        : true,                        
                     // enable debug messaging ( to console.log )
     
      loadingImg   : "/img/loading.gif",          
                     // loading image.
                     // default: "http://www.infinite-scroll.com/loading.gif"
     
      loadingText  : "Loading new posts...",      
                     // text accompanying loading image
                     // default: "<em>Loading the next set of posts...</em>"
     
      animate      : true,      
                     // boolean, if the page will do an animated scroll when new content loads
                     // default: false
     
      extraScrollPx: 50,      
                     // number of additonal pixels that the page will scroll 
                     // (in addition to the height of the loading div)
                     // animate must be true for this to matter
                     // default: 150
     
      donetext     : "I think we've hit the end, Jim" ,
                     // text displayed when all items have been retrieved
                     // default: "<em>Congratulations, you've reached the end of the internet.</em>"
     
      bufferPx     : 40,
                     // increase this number if you want infscroll to fire quicker
                     // (a high number means a user will not see the loading message)
                     // new in 1.2
                     // default: 40
     
      errorCallback: function(){},
                     // called when a requested page 404's or when there is no more content
                     // new in 1.2                   
     
      localMode    : true
                     // enable an overflow:auto box to have the same functionality
                     // demo: http://paulirish.com/demo/infscr
                     // instead of watching the entire window scrolling the element this plugin
                     //   was called on will be watched
                     // new in 1.2
                     // default: false
     
        },function(arrayOfNewElems){
     
         // optional callback when new content is successfully loaded in.
     
         // keyword `this` will refer to the new DOM content that was just added.
         // as of 1.5, `this` matches the element you called the plugin on (e.g. #content)
         //                   all the new elements that were found are passed in as an array
     
    });

    Custom trigger, non-automatic. Twitter-style

    In 1.4 you can trigger the loading of the next page of content at will. You’ll first unbind the default behavior. And then trigger the next pull whenever you like..

    // unbind normal behavior. needs to occur after normal infinite scroll setup.
    $(window).unbind('.infscr');
    // call this whenever you want to retrieve the next page of content
    // likely this would go in a click handler of some sort
    $(document).trigger('retrieve.infscr');

    Demo of the triggered infinite scroll functionality.

    How does it work?

    There is a little known feature in the .load() method that lets you specify the CSS selector of the html you want to include. jQuery will load in any local URL, then parse the html and grab only the elements you’ve defined with your selector. This allows for some pretty fun shit: client-side transclusions (a la purple include) ; and some really kickass shit when you combo it with a local php proxy.

    This is really the meat of the code:

    // load all post divs from page 2 into an off-DOM div
    $('
    ').load('/page/2/ #content div.post',function(){ 
        $(this).appendTo('#content');    // once they're loaded, append them to our content area
    });

    So it basically leverages that load() method at its core. It’s basically scraping your existing page structure, which means you don’t need to code any custom backend stuff to enable this functionality! Booyah, right?