Question: Headscape tabs

David Bridle writes: How did you get the tabbed menu to work in the headscape website? 

The navigation on the Headscape website is built using the Javascript library jQuery. I have mentioned jQuery a number of times before so I won’t bother to repeat myself here.

I don’t claim to be a javascript expert but I have made Headscape as accessible as I know how. I am sure there will be people out there that could have done a better job but I will share what I did (for better or worse).

I am not going to get into too much code as I am not the right person to teach that. I also think it is more important to show you the techniques rather than post code that can be copy and paste into your own site. If you want to learn how to actually reproduce what I have done then I recommend the excellent documentation on the jQuery site or the designers guide to jQuery.

Choosing AJAX

It was important to me that the content found under each tab was accessible with Javascript disabled. My initial thought was to include all of the tabs in the page load. However, it quickly became obvious that this would make the download too large and would not allow for adding content in the future.

Eventually I concluded that I wanted to use AJAX. Using Jeremy Keith’s HIJAX approach I built one page for each of the case studies found under the tabs. I then linked to these from the homepage tabs using normal hrefs. Clicking on each tab would load the appropriate page.

Screenshot of Headscape website with Javascript disabled

Each of these individual pages were complete with a header and footer as well as the content I wanted to include on the homepage.

The Javascript

The next step was to create some javascript which prevented the default action of loading the entire page, and instead load only the portion I wanted.

This was achieved with a function that was triggered on clicking each tab. The function was attached unobtrusively (rather than included in the HTML itself) so I could easily remove it later if I wanted to alter the way the site worked.

The function carried out the following actions:

  • It captured the url of each link
    $("#csMenu a").href
  • Append to the links the specific element I wanted to import using AJAX
    var addr = $("#csMenu a").href + " #caseStudies
  • Load that content into the appropriate place on the page (which had the id = csCont)
    $("#csCont").load(addr)
  • Applied some of the inbuilt effects in jQuery to make the animation fade in and out.
  • Prevented the default action
    return false;

In reality it was slightly more complex because I needed to trigger additional functions to add a popup facility to some of the links within the imported content. However, fundamentally that was it.

The problem with AJAX

The only problem that remained were screen readers. Although the site worked with Javascript disabled the use of AJAX would confuse screen readers. Without getting too technical Screen readers are able to run Javascript but don’t always realize when AJAX has updated the page.

A lot of people cleverer than me have been struggling with this issue and failed to come up with a solution. That is why some developers such as Brothercake recommend against the use of AJAX.

I had good reasons for the choice of AJAX (which I won’t get into here) and so had to find a solution. This ended up being a simple hidden message telling screen reader users to disable Javascript. Thisl enable them to navigate the additional pages without problem. This message was the first item within the body tag and was hidden using CSS so it was only heard by Screen reader users.

No doubt I will receive criticism for this decision and to some extent rightly so. It presumes users know how to disable Javascript in their screen reader. Even if they do, it is not an ideal solution. Users should not be required to change preferences before they can view a site. However, the state of screen readers is far from ideal either, and it is was the best compromise I could find.

So there you have it. That is how I produced the tabs on the Headscape website. I would be fascinated to hear what other approaches people would have used. How could I have done it better?

  • http://www.buy-our-honeymoon.com/ Andrew Green

    An approach that we’re planning on using for Buy Our Honeymoon (but haven’t yet done so) is to have a switch on an Accessibility Options page that will set a “no-ajax” cookie.
    Assuming then that the main pages aren’t static HTML, the site will check for the presence of this cookie and, if it’s there, omit the Javascript for the Ajax functions from the delivered page. That way you can retain some useful progressive enhancement with Javascript, whilst allowing users to disable the Ajax stuff if they want to.
    Of course, the link to the Accessibility Options page needs to be non-Ajax itself in the first place!
    Cheers,
    Andrew.

  • http://cole007.net Cole Henley

    Interesting post Paul.
    The simplicity and power of jQuery is making me much more experimental in my use of ajax. One question/thought – if your message for screenreaders relates to the use of javascript on the site then why not use javascript to add it so that with javascript disabled screen reader users won’t get a message that doesn’t relate to them?
    Have seen this a lot where message relating to behaviour are hard-coded into the HTML (as a handle to be manioulated by javascript) when every other aspect of a site’s behaviour has been carefully separated/progressively enhanced/gracefully degraded (insert catchphrase of choice).
    Just a thought,
    Cole

  • http://www.creativewebspecialist.co.uk Warren Buckley

    Hi Paul,
    I have learnt something new about the jQuery library which is the “.load” event. I like the idea of how you loaded in external content from another page of your site.
    I like that this will degrade gracefully if JavaScript is disabled. In my personal opinion I think you should only do optimisation for screenreaders if your stats show you that people are browsing to your site using a screen reader.
    Additionally I don’t think many screenreader users will be reading a site about managing websites in my opinion, your audience will be people who will most likely be running the latest browser versions and operating systems, due to the background of the subject.
    Anyway my 2 cents worth, as always keep up the good work.
    Thanks,
    Warren

  • http://cole007.net Cole Henley

    @warren
    Nice thought but web stats won’t pick up screen reader use. Screen readers do not themselves view web sites (the exception perhaps being the use of text-based browsers such as Lynx) but rather sit over the users web browser of choice.
    Therefore, the header requests that generate your server stats (or alternatively the javascript requests that generate client-sided web traffic statistics) will only show the web browser being used and not the tool that is being used to interpret what the browser returns,
    Cole

  • http://boagworld.com Paul Boag

    @Andrew… love the cookie approach. I’ll have to think about it some more but at first glance it sounds like a winner.

  • http://www.roryf.co.uk Rory Fitzpatrick

    Thanks for the post Paul, some responsible scripting techniques on the go there!
    I had thought that screen readers wouldn’t pay attention to hidden content, but on closer inspection you’ve used some nifty negative positioning which I assume will work?
    For an accessible approach to Ajax, check out the W3C ARIA spec (http://www.w3.org/WAI/intro/aria), it allows you to mark an area of a page that might be updated via Ajax and alert the browser to when this happens. Its not got very wide implementation yet, only FF3 and Webkit as far as I know, but its a promising solution.
    Cheers
    Rory

  • http://www.simongriffiths.name Simon Griffiths

    I’m not sure why you didn’t use CSS to do this in the first place but I am guessig it is because of browser compatibility. Have you had a look at the menu system developed by Steve Gibson that does the SecurityNow podcast? He has opensourced the code at http://www.grc.com/menu2/invitro.htm.
    The interesting thing about this is that it is pure CSS, and is compatible with all browsers pretty much (look at the code and you will see he has spent a lot of time on this). In theory you could use this to do pretty much the same thing, with no scripting at all, and therefore maximum accessibility.

  • Damien Lebrun

    @Simon: the Ajax solution scales better.
    Each case study has its own page, and the home page will display only 6 of them. The Ajax solution avoid duplicate content without page reload.
    @Paul: a solution that might work would be to use a fragment identifier:
    - Here’s a typical case study link href: “/clients/xyz.htm”;
    - with js on, it becomes “#studycase:xyz”;
    - when the link is clicked “/clients/xyz.htm” is loaded and inserted in an element with the id “studycase:xyz” and the even should not be cancelled so that the browser focus on the “studycase:xyz” element.
    If the focus can happen after the new content is inserted (is it possible?), the feedback won’t only be visual and it should be working with a screen reader as well.
    Also using something like the history plug-in (http://plugins.jquery.com/project/history) it won’t break the back button and will allow bookmarking the case study.

  • http://www.webglossary.co.uk Gilbert

    I was wondering what sort of effect the single page site approach was having on your stats? Specifically pgae views in the traditional sense.
    The AJAX approach of loading the case study fragment from another page would mean that in things like Google Analytics, looking at a case study wouldn’t register as a page view.
    I guess if you’re using stats from log files, looking at a case study would register as a page view.
    Then I guess you could also just look at where people were actually clicking on the page.
    There you go I’ve answered my own question I think.

  • http://www.thereisnocat.com/ Ralph Brandi

    Paul,
    Rather than setting up a separate accessibility page as Andrew suggests, perhaps a better approach would be to just place the option of whether to use Ajax or not at the head of the page. This is the approach I took on a site for the North American Shortwave Association. One section of the site contains a database of shortwave radio stations that the club’s members have heard over the years. I used the opportunity of creating the site a couple of years ago to teach myself Ajax, but part of the audience for the site is blind, so I had to make sure it was accessible. My solution was to put a couple of radio buttons at the top of the page asking users if they wanted to open the details within the page or in a new page. Then the event handler for each item checks to see if the choice to open within the page is checked. If it is, the Ajax query is used; if it’s not, the PHP-based query is used. I also set a cookie when the radio buttons are checked so that the chosen option is retained. You could throw this option off the edge of the page; I chose to leave it visible for everyone. I also use the selection of option to define whether sorting of the table is done in page or with a page refresh (but don’t mention that in the radio buttons; the label would get too long if I did).
    You can see this in action on the NASWA site at http://www.naswa.net/logs/. Search for a country like “United Kingdom” and you’ll get a number of results, along with the radio buttons I mentioned. I would probably write the Javascript there a little differently if I were creating the site today, but you’ll get the idea.

Headscape

Boagworld