AJAX, JavaScript and accessibility

With the advent of mass-hype for building AJAX solutions, I find it necessary to shed some light of AJAX and JavaScript implementations and how they relate to and affect accessibility, and to explain how they can both co-exist; that one doesn’t exclude the other.

What is a progressive enhancement/unobtrusive JavaScript approach?

First, a good JavaScript approach is about implementing JavaScript in an unobtrusive way. Basically, what this means is avoiding some basic bad implementations:

  • No more inline event handlers in HTML elements, meaning that code like this should never be used:

    <div onclick="doSomethingAnnoying()">A div</div>)

  • Definitely never ever use javascript: links, like this:

    <a href="javascript:pleaseTeachMeProperJavaScript()">A destroyed link</a>

  • No inline JavaScript blocks in your web pages at all.

How should I do it then?

Common things to think about are:

  • Have all your JavaScript in external files, for better accessibility and performance (since JavaScript files are cached by the web browser and only needs to be retrieved once), and then also apply events to elements from there.
  • Only apply JavaScript event handlers to elements that already have built-in functionality for communicating, like links and submit buttons.
  • Make sure the web site functions without JavaScript. JavaScript is supposed to be used to spice things up based on already existing functionality, not to be the corner stone that the web site is totally depending on.

Give me a good example

Sure! For instance, say you want to apply a certain JavaScript event to some links in your web page that shows an information layer (e.g. a div that is initially hidden). How do you do it?

  1. Create your link elements:

    <a href="my-details.php" class="show-info-layer">My details</a>

  2. Include your external JavaScript file:

    <script type="text/javascript" src="linkEvents.js"></script>

  3. Use the window.onload event, which is triggered when the web page is fully loaded, to then apply your events to desired elements. There are many different ways of doing this and how to handle events, so here’s a simple example:
    
    window.onload = applyEvents;
    function applyEvents(){
    	if(document.getElementById && document.getElementsByTagName){
    		var arrAllLinks = document.getElementsByTagName("a");
    		var oLink;
    		for(var i=0; i<arrAllLinks.length; i++){
    	    	oLink = arrAllLinks[i];
    			if(oLink.className.search(/show-info-layer/) != -1){
    				oLink.onclick = function (oEvent){
    					var oEvent = (typeof oEvent != "undefined")? oEvent : event;
    					oEvent.returnValue = false;
    					if(oEvent.preventDefault){
    						oEvent.preventDefault();
    					}
    					document.getElementById("my-details").className = "display-block";
    				}
    			}
    	    }
    	}
    }
    

The result is that web browsers that have JavaScript activated and that support the document.getElementById and document.getElementsByTagName methods will cancel the links navigation to the my-details.php page and instead show an information layer directly in the page. For those who don’t match that criteria, it will simply redirect them to the my-details page. Offering something extra for those with JavaScript enabled but still degrading nicely and being fully functional to others.

Let’s break the script down, what happened?

window.onload = applyEvents;

First I tell the window to call a function when it’s onload event is triggered, i.e. the page is fully loaded. Notice: no parentheses after the function name, in that case it would’ve been called instantaneously.

In the applyEvents function, the first line is this:

if(document.getElementById && document.getElementsByTagName){

What it does is using an approach called object detection to see if the document object supports the two methods we want to use: document.getElementById and document.getElementsByTagName (these two are widely supported by most web browsers, don’t worry).

var arrAllLinks = document.getElementsByTagName("a");

Gets a collection of all link elements in the page (could be done in a more effective manner with the getElementsByClassName script).


for(var i=0; i<arrAllLinks.length; i++){
	oLink = arrAllLinks[i];
	if(oLink.className.search(/show-info-layer/) != -1){

Loops through the collection of links to find the ones with a certain class name. Note the usage of the variable oLink to avoid doing several checks in the array, and that it is also declared outside the loop. All for performance reasons.


oLink.onclick = function (oEvent){
	var oEvent = (typeof oEvent != "undefined")? oEvent : event;
	oEvent.returnValue = false;
	if(oEvent.preventDefault){
		oEvent.preventDefault();
	}
	document.getElementById("my-details").className = "display-block";
}

Applies the onclick event to the matching link/-s and cancels their default behavior. The check for oEvent in the event handling is the standard way of event handling, while event is for Internet Explorer’s flawed and proprietary event handling. Now a click will instead show the information layer element.

What about AJAX, it said so in the title?

With the good practices and examples I’ve given above, it’s pretty much all about using the same knowledge when doing something AJAX-based. With my AJAX library, ASK, it was my attention to implement it in that manner, and also cater to well-known usability problems like back buttons that work, impossible to bookmark a specific state of an AJAX-based page etc, at the same time. I definitely urge you to take a look at it and play around with it.

Something to think of is that when it comes to screen readers is that they might support the JavaScript you use but won’t notify the user that something has been updated in the page. For more on this discussion, please read Derek’s Javascript and Accessibility (yes, I saw the name of his post after I initially posted this one… πŸ™‚ ).

 

Related reading

32 Comments

  • Per Zimmerman says:

    You should check out the Behaviour.js: http://bennolan.com/behaviour/. It makes it very easy to apply javascript code to elements. It uses a nice function <code>getElementsBySelector </code> to retrieve elements using CSS selectors.

  • Tim says:

    Good article Robert, very usefull for those who aren't very familiar with the terms progressive enhancement and unobtrusive js.

  • Inspired by Behaviour, event:Selectors was released a couple of days ago, with the intention to more closely integrate with the Prototype library.

  • I think you should mention here <code>addLoadEvent()</code> instead to applay your onLoad event to window and overwrite all other :-).

  • How do I do this in a web application. For instance I need to let the user select a name from a directory of over 50,000 names. Right now I have a popup that allows the user to select names from the directory. When they double click the name or click the name then click the select button the name is copied from the popup to the calling form. The popup has previous and next links and a find form. When the user double clicks, clicks the select button or clicks the close button, the popup closes. The popup form will not work without javascript.

    Is there a better way?

  • Johan says:

    @Nyman R.: possible you could include a zipped working example

  • Johan says:

    @Nyman ++

    The whole idea is to show a div with info and when JS is off to relocate to a html page with that info?

  • Robert Nyman says:

    Thanks for your comments.

    When it comes to JavaScript libraries in general, I’m not that much into them. Even though many of them are getting very lean, they’re usually still too bloated for my taste and always have things that won’t be used.

    Another problem is that way too many people start using libraries before actually learning why and how JavaScript work. They then have too much scripts on their pages and if things go wrong, they don’t have a clue why or how to address it.

    Then again, if you’re a seasoned web developer and prefer existing libraries where you understand everything that’s in them, it’s totally up to you.

    Jeena,

    The reason I didn’t bring that up is that I wanted to keep the explanation as simple as possible, instead of straying into the problems of assigning multiple events (because it’s only a problem in that case). If anyone is interested in how to do it, take a look at the addWindowEvent function in the ASK JavaScript file.

    Tanny,

    It’s hard to answer that one without seeing the axtual context, but my general advice is to build the web application so it functions without any JavaScript at all to begin with, and then apply scripts as an enhancement layer on top it.

    In your case, my guess is that there should be another page where they can add users from the directory, but for people with JavaScript support you can add events to import users on the fly to your current page with an AJAX-like approach.

    Does that explanation help you at all?

    Johan,

    Yes, that’s the whole idea of the example, just to show how to do it unobtrusive and in a progressive enhancement-manner.

  • Stuart says:

    Robert: Good stuff here, it reminds me to start teaching everyone I work with to stop using the inline event handlers. One benefit of this approach is it also makes it easier to build up your own collection of useful scripts that can just be dropped into a page.

    I guess that's good advice too for anyone that already knows this stuff. Make it your mission to help a fellow developer use javascript properly if they don't already know.

    I think maybe you could have mentioned the use of an addevent function as in the real world it's going to be common that you need to make use of more than one onload event. Alternatively an easily digestible explanation of the purpose of addevent functions could be part 2. πŸ™‚

  • Robert Nyman says:

    Stuart,

    Thank you!

    Yes, event handling sounds like a good idea for a part 2, but I wanted to keep this as simple as possible.

  • Chris says:

    Robert, thanks for this nice article. In english πŸ˜‰

  • Thanks Robert, the mist is starting to clear… πŸ™‚

    Looking forward to the follow-up!

  • Robert Nyman says:

    Chris, Steve,

    I'm happy to abide! πŸ™‚

  • Martin Kliehm says:

    I don’t get why you need to create an event onload with a rather complicated JavaScript function, when you could have something as simple as:

    <a href="my-details.php" onclick="showInfoLayer(); return false;"> My details</a>

    It won’t mess with the link either when JavaScript is turned off. Or do I miss some important argument?

  • Robert Nyman says:

    Martin,

    To begin with, the whole point is to separate content (HTML) from interaction (JavaScript); they should never be mixed together.

    Second, with inline event handlers, they have to be downloaded by the web browsers all the time, as opposed to a JavaScript file that gets cached after it has been retrieved the first time.

    Third, it’s about maintenance. If you have several web pages with different interaction you want one central place to control it, as opposed to having to go into each element in evey page to adjust things.

  • Martin Kliehm says:

    Hm, in my opinion it’s just a function call, it’s no fancy JavaScript. I agree on utmost separation of view and control, but this seems a bit radical even for me. If the W3C gods hadn’t intended us to use events, they wouldn’t have included them in XHTML. πŸ˜‰

    Second it’s just a few bytes to download – for example, you don’t take processing power for the JavaScript loop into account either. Both is just neglectable.

    I can understand your third reason, but again it’s just a function call. And it’s very simple (as opposed to DOM tree walking) and generic, so I can’t see much reason for change either. For anything more complicated I would use server-side includes to ease maintenance. After all, if you would really use this to show/hide layers, their location and maintenance (not to mention accessibility) would require a good concept anyway.

  • Martin Kliehm says:

    After talking to a colleague I can see a few scenarios where your method is more convenient. There were cases where I added events using JavaScript just like you proposed rather then writing several lines of onmouseover="doSomething()" onmouseout="doSomethingElse()" onfocus="doSomething()" onblur="doSomethingElse()", which can really get annoying.

    By the way, I loved your example pleaseTeachMeProperJavaScript()!

  • Robert Nyman says:

    Martin.

    Well, the example above is very simple but in most, of not every, scenario you will have a lot of script in the page. To me a function call is still interaction, no matter how small. If it only had been one link, then you would naturally use <code>getElementById</code> instead.

    In the end, to me it's about doing things properly all the time. If one gets used to bad practices, they just tend to stick around for too long… 😐

    And thanks for liking the example! πŸ™‚

  • […] lioteca para facilitar el desarrollo: Backbase AJAX Library. Y, finalmente, accesibilidad: sob […]

  • […] or stray from conventions just to spite. If you write valid and semantic markup, and add JavaScript in an unobtrusive fashion, your web site has come a long way […]

  • […] AJAX apps, make sure that it works without JavaScript as well, apply all the scripts in an unobtrusive fashion. I’m just glad that ASK passed the test with i […]

  • Matt Asquith says:

    Can you please tell me how to start the slideshow onLoad? (ie automaticall start the slideshow on page load).

    Thanks!

    M

  • Robert Nyman says:

    Matt,

    There's isn't any autoplay mode, but instead more like a regular PowerPoint slideshow. If you only want to have a slideshow of images, maybe JaS is a better alternative for you.

  • […] what you will). It is basically the principle of unobtrusive JavaScript applied to Ajax. AJAX, JavaScript and accessibilit […]

  • […] velopers, and countless of people have made their stab of solving it. When I wrote my post AJAX, JavaScript and accessibility some commenters were asking for a fol […]

  • […] find tips arranged by specific disability. Accessible Javascript and AJAX AJAX, JavaScript and accessibility from Robert’s Talk. This is a […]

  • […] th it is, in my eyes, not complete. A couple of links explaining it more thoroughly: AJAX, JavaScript and accessibility Unobtrusive Javascript […]

  • […] AJAX, JavaScript and accessibility […]

  • […] AJAX, JavaScript and accessibility With the advent of mass-hype for building AJAX solutions, I find it necessary to shed some light of AJAX and JavaScript implementations and how they relate to and affect accessibility, and to explain how they can both co-exist; that one doesn’t exclude the other. […]

  • […] AJAX, JavaScript and accessibility […]

  • Gold says:

    I have a problem that drive me crazy .. and if some one can help .. it would be appreciated .. I have 2 pages .. page1,page2 .. page1 showing the information of page2 and continue to refresh every 5 seconds using ajax .. page2 has javascript included and it works when I'm showing page2 only .. but when page1 calls page2 to show its contents .. the javascript dont work… please help

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.