A few days ago, I explored the concept of creating an "infinite scroll" effect using jQuery (with AJAX) and ColdFusion. The idea behind infinite scrolling is that as the user scrolls down the page, more content is dynamically appended to the content area such that the user can keep scrolling on and on forever (or at least until they run out of data or their browser crashes). In the comments to that post, George Bridgeman, Gareth Arch, and myself discussed the pros and cons of this kind of approach.
With an infinite scroll effect, there is arguably more demand placed on the content sever since requests for more content are made as quickly as the user can scroll (which is quite quickly). Of course, a similar demand could be placed on the server if the user kept clicking the "Next" pagination button in fast succession. But, server issues aside, does this effect provide a good user experience? Strictly from a personal standpoint, yes, absolutely - I've seen this effect used many times and I always appreciate it.
But going beyond the emotional perception, it was raised in the discussion that continually adding content to the page could quickly overload the browser's DOM and cause a crash (or at least some sluggishness). To this point, Gareth brought up the idea that if we could dynamically alter the content at both the bottom and the top of the document, we could keep the infinite scroll effect without creating an obese document object model. I liked this idea a lot, and started playing around with the following "bidirectional infinite scrolling" effect.
NOTE: Sorry the scrolling doesn't show up very smoothly in this video (but trust me, it's smooth, not jumpy).
Now that you've seen the "demo" video, here is a closer examination of the code. Because there is a lot of code, I skipped a bunch of it and just concentrated on what I felt was the most exciting part: dealing with window offset as content is both added to and removed from the page.
At the abstract level, this is not much more complicated than a downward-only infinite scroll; we're still just thinking about a view frame and the offset of the content. The only abstract difference this time is that we are thinking about the top of the content as well as the bottom:
At the abstract level, it's just more math. At the practical level, however, things get a lot more exciting (read as: complex). In the downward only version, when we added content to the bottom of the page, the scroll bar changed, but the view frame offset did not; as such, it was not an issue. This time, however, we are adding and removing content from the top of the document. Both of these actions (add and remove) have direct and obvious effects on the view frame offset. As such, when we alter the top of the content, we have to take care to maintain the user's "perceived" position within the document.
In order to do this - keep the user in the "same" spot as the content is mutated - we need to adjust the view frame offset manually. To do that, however, we sort of need to know the height of the content being added or taken away. And, to do that, it is sort of required that the content being added or taken away has an easily calculated height. And, to ensure that, we sort of need the new content to not "flow" into the old content (ie. we need a clean horizontal cut between content chunks).
As you can see, at the practical level, a bidirectional, infinite scroll requires a few more content constraints than the downward-only infinite scroll. If we can embrace these new constraints, however, building the effect isn't too much of a nightmare. In the following code, I am using jQuery to create an AJAX-powered, bidirectional infinite scroll effect that gets its content from a ColdFusion server. The ColdFusion code will shown at the end.
I won't go into too much explanation at this point since I have both video and heavily documented code. The one thing I will say, however is that in the above code, I differentiate the "desire" to change the content from the "decision" to change the content. By that, I mean that I have one function, isMoreListItemsNeeded(), which looks purely at the content offset relative to the view frame when flagging an area (top or bottom) as needing more content; I then have a different function, checkListItemContents(), which takes those "mutation flags" and decides whether or not to put them into action (factoring the min and max record offset into the logic). This separation made the problem easier for me to think about.
If you are interested, here is the ColdFusion code:
The additional constraints placed on the content - specifically the requirements of clean horizontal lines - definitely limits the kind of scenarios in which a bidirectional infinite scroll effect can be used. I'll put my thinking cap on to see if I can come up with a clever way to use this in conjunction with floating content.
Want to use code from this post? Check out the license.