Friday, 27 June 2008

Graceful Lists

In a project I was working on recently I needed to return a list. I can't remember what the list consisted of (okay not that recent), but each item in the list was going to require some processor power to generate the item's associated content. I didn't want to take the standard server side approach of building the list prior to rendering the page. While the list size was fixed, the processing time for each item varied, making timeouts a factor. The age of the data was also important, preventing the possibility of server side caching over any length of time.

The proposition I came up with is not an uncommon one. The idea was to create a page which loaded each item on the list incrementally using XHR. But what about browsers without JavaScript or with JavaScript switch off? Initially, I considered drastically reducing the amount of results returned by the page using paging. My main concern here was that while you can generally tell whether the user's browser is JavaScript enabled from the User Agent, it's impossible (as far as I'm aware) to detect whether the user has opted to disable JavaScript, on the first request to the server. Also, paging drives me nuts, I prefer to scroll!

I had assumed browsers broadcasted the status of scripting abilities and alike in the header of each request. I have no reason for assuming this, other than it sounds like quite a good idea to me.

Without being able to reliably detect a browser's scripting ability, the paging solution risks serving an empty page to browsers with JavaScript disabled. While investigating this problem I came across 123-reg.co.uk. 123-reg.co.uk uses a similar pattern to the one I've suggested, for displaying domain availability. User's with JavaScript enabled browsers see the list built in front of them using Ajax. Everyone else is served a pre-rendered list. What is clever (in its simplicity) is the way in which 123-reg.co.uk detects JavaScript. On the page where the user enters their search terms, a script modifies the action URL of the form to include the parameter "ajax_enabled=true". The results page is rendered based on the value of that parameter.

The example provided by 123-reg.co.uk is a great way of detecting script. The problem with this approach is the reliance on the search page (to modify the URL), my list exists on a page that is a possible entry point to the application. I'm not making it easy for myself. As a result of the previous example I also toyed with the idea of a page that assumes JavaScript is switched on, but with a META Refresh tag in the header. If JavaScript is enabled, remove the META tag. If JavaScript is disabled, the page redirects (via the META tag) to a pre-rendered page. I was put off by the idea of effectively breaking the Back button for users without JavaScript.

My eventual implementation was a pre-rendered list that assumed JavaScript was switched off. This list doesn't contain any of the extended content, so no heavy lifting that originally had me concerned. Each item on the list instead provides anchors to a second page that generates the extended content. Once the page is loaded, JavaScript enabled browsers move though each of the items, dynamically adding the extend content. This solution works extremely well for script enabled browsers, everything on one page with visual feedback for the processing going on server side. Unscripted browsers have the burden of an extra click to and from the extended content, but the initial page load dramatically reduced when compared to the server side approach described at the beginning of this post.

This particular problem made me think a lot about my audience and the merits of graceful degradation. Who am I making this application for? And more importantly, who am I willing to exclude? Within a corporate Intranet, these decisions are sometimes made by company guidelines and policies, a lot of the time by time constraints. In the open web, (I believe) accessibility is extremely important. If you are building something like Facebook, where you a targeting a market defined by age, gender or interest, your application should be accessible to text readers and main stream browsers alike. The experience has also showed me that I'm not so bothered about catering for users that have purposefully restricted the capability of their own browser (switching off script or CSS). I guess there might be a valid reason for doing this, but I'm unable to come up with one.

Twitter Updates