Category: JavaScript

Accessible Ajax: OmniTI

PHP all-stars, OmniTI, recently launched their web site; Jon Tan and I had the pleasure of aiding in its creation.

You can read more about the site’s development on Jon’s blog, starting out with evolving OmniTI’s brand with their team through to a review of the site’s build. Here I’m going to show you what we did to enhance the site with some JavaScript functionality and how we ensured that content updated using Ajax was as accessible as possible.

Progressive enhancement

Progressive enhancement firmly in mind, we wanted to provide users immediate access to some useful information, such as contact details and the search form. The JavaScript functionality is strictly separated from the structured content of the site into external files – no scripting in the markup.

The contact details and search form have dedicated pages on the site, which serve as fall-backs for cases where JavaScript is unavailable. When JavaScript is disabled, the search and contact links will take you to the respective pages. If JavaScript is enabled, it runs when the page loads and sets up everything that it needs for the added functionality.

We opted to use the jQuery JavaScript framework to implement these features. Using a framework allows you to quickly build prototype features and makes code easier to maintain in the long run. We specifically chose jQuery because it is fast and lightweight.

Sensible Ajax

The additional layers of markup for both the contact details and search layers are requested from the server using Ajax, which jQuery makes really easy. It’s common for such layers to be embedded in the page markup and hidden using CSS when the page loads. The information in these layers are for convenience and is available on other pages of the site, so it doesn’t need to be on every page. Using Ajax in this way also allows the markup for those layers to be easily maintain server-side.

Having requested the markup as necessary using Ajax, it may be tempting to inject the markup into the DOM straight away. If you do this and disable CSS, the markup will be visible at the top of each page, just as it would if you had embedded it in every page on the site. It just doesn’t need to be there. Instead, the markup is held in a JavaScript variable rather than injected into the page from the start. These layers are only added to the page when they are needed. This way, even if CSS is disabled, the content is only there when it needs to be and doesn’t interfere with the rest of the content.

The interface

When a visitor hits either the contact or search links at the top of every page, if JavaScript is enabled, the appropriate layer of information slides out from the top of the page. Hitting the close button or the link that activated the layer removes the layer from the DOM rather than simply hiding it with CSS. As a nice extra, hitting the contact link when the search layer is open will toggle between the two layers.

That’s all fine for the majority of users. Let’s make sure we think about other users who may have different, and diverse, needs.

A more accessible interface

Sighted users see the lovely jQuery slide down effect when they click one of the activating links; it grabs their attention and shows them that new information is on the screen. If you can’t see, you need different feedback to tell you what’s happened when you followed the link, otherwise you might think that nothing has happened.

For keyboard users, which includes most screen reader users, we need to give the added layer focus in some way. JavaScript to the rescue; we can move keyboard focus to a focusable element using some simple code. If we don’t do this, users will have to navigate a long way through the page to get to the place that the new layer has been added to the DOM. As you might imagine, few users will be patient enough to search around for the new information. In fact, they may not even know that new information is on the page.

Sometimes it will make sense to inject new information into the DOM just after the element that actions the addition. Doing so will help screen reader users to find the information because the very next thing they read is likely to be that new information. However, for the OmniTI site we wanted to add the new layers to the top of our page for visual effect. So, we need to tell JavaScript to focus on something appropriate within the new layer.

Using focus for feedback

We need to pick a focusable element in the new layer we’ve added to the page, i.e. a link or a form element. Conveniently – although, some might say by design – there are appropriate elements at the start of our new layers. In the search layer, it makes sense to focus on the search input of the form. In the contact layer, the first element is an email link, so we can put focus on that.

Keyboard focus can be brought about easily by calling focus() on the required element, so long as the element is focusable. For example, after injecting the layer, we can pick it out the target element and give it focus:

document.getElementById('myLink').focus();

Ironing out some creases

During testing, the most prevalent screen reader software, JAWS, coped well when focusing on form elements. However, it doesn’t always seem to like focussing on links; the screen reader’s buffer (its copy of the page’s DOM) seems to get updated correctly, but its virtual cursor is not always moved when focus() is called in the JavaScript.

Where Ajax is involved, problems can occur when the screen reader updates its virtual buffer before the Ajax call is complete. The response to the Ajax call may result in a change in the browser, but that change is not passed on to the screen reader. As our Ajax calls are only executed when the script is initiated, that’s unlikely to be the case this time.

As a focusable element, the target link should be able to receive focus with no trouble, but in conjunction with injecting elements into the DOM, it doesn’t always work. However, there’s a fix.

Technically, setting a tabindex value of -1 on an element should allow any type of element to become focusable. (You can read more in Gez Lemon’s Making Ajax Work with Screen Readers.) Obviously, the link should be focusable anyway, but using JavaScript to set a tabindex value of -1 on our link before we give it focus results in more reliable behaviour from JAWS.

Update: I found out from Christian Heilmann that this is likely to be a symptom of Internet Explorer’s hasLayout issues, which should mean that it can be fixed by triggering hasLayout on the target element.

We’ve got one last problem to iron out. In some browsers, setting a tabindex value of less than zero will remove the element from the tab order of the page. Keyboard users will often make use of the Tab to navigate around the focusable elements of a page. The tab order is the sequence in which these elements are given focus as a user tabs around a page. As our link should be in that tab order by default, we’ve just removed it by messing with its tabindex. Setting the tabindex value to zero (and possibly blank, but I’d need to double check) will put the link back in its place in the tab order. I don’t recommend setting tabindex in markup, but if you happen to be doing so, you should set the tabindex back to its expected value.

JavaScript, abbr and Internet Explorer

The other day I wrote about how screen readers handle abbreviations. I mentioned the lack of support for the abbr element in Internet Explorer (IE 6 and below) and how it may have led people to believe that screen readers working with Internet Explorer don’t support it either. I went on to explain that modern screen readers do support both abbr and acronym elements, but perhaps not in the way that developers expect.

I’ve been doing a bit of poking around and it seems that abbr elements have been available in Internet Explorer’s Document Object Model (DOM) for some time, which I didn’t realise. I’ve been able to access the title attributes of abbr elements as far back IE 5.01. However, what we haven’t been able to do is style these elements with CSS or access their child nodes (i.e. their content) with JavaScript; that is until IE 7 introduced proper abbr support.

There have been a few ways to force IE 5 and 6 to support abbr; from using extra markup, through hacking it with JavaScript, to using the html namespace to trick the browser. Now it seems there’s been a really simple JavaScript solution that’s lain dormant for about four years.

A simple JavaScript fix using createElement()

Thanks to a tip from Sjoerd Visscher, Jeremy Keith observed that we can con Internet Explorer into understanding abbr and persuade it to recognise the element as a proper part of its DOM.

So, armed with this new knowledge from Sjoerd and Jeremy, I ran another test using this createElement() JavaScript fix. The results show that IE 5.5 and IE 6 will add abbr to the DOM properly if you add this at the beginning of your JavaScript:

document.createElement("abbr");

You can style it and it even displays the title attribute as a tool tip for you! Lovely! Internet Explorer 5.01 doesn’t play ball – why am I not surprised?!

Remember, we’re not doing this for the benefit of screen readers. The modern screen readers JAWS and Window-Eyes can expand the contents of abbr and acronym elements using their title attributes. All we are doing is making sure Internet Explorer itself is fully aware of abbr, enabling us to style it with CSS and manipulate it properly within the DOM. So, whether or not you want to do this is entirely based on what you do in the browser – don’t do it for the sake of assistive technology.

Further reading

Removing alt tooltips in IE with JavaScript

There was a bit of debate on Anne van Kesteren’s blog last year about alt attributes being rendered as tooltips by some Windows browsers, most notably, Internet Explorer.

Following the W3C specifications, there’s no reason for alt attributes to appear as tooltips. However, there’s nothing to say that ‘alt tooltip’ behaviour is wrong. Certainly, alternative text should appear if an image does not render on the page.

Working on a recent project, the client asked why the descriptive alternative text for an image appeared when they moused over the header image that spanned the top of each page of content. They wanted the alternative text to either not appear or be set to text optimised with keywords.

Update: When first writing this article I was under the impression that screen readers would announce all images followed by their alternative text. Consequently, I’d put alternative text in for all images in markup because I’d personally prefer to be told, “Hey, this image is of an old oak tree with twisted branches” than “There’s an image here, but we don’t want to tell you what it’s in it”! I’ve since found out that JAWS will not even announce the presence of an image that has an empty alt attribute. If that behaviour can be relied upon in all screen readers, the most appropriate solution to our problem may have been to leave the alt blank. I think the JavaScript solution I provide below is still useful should you wish to get Internet Explorer to present correct tooltip behaviour.

What could we do?

The alt text was fit for purpose and we refused to bend the rules for the sake of a bit more SEO. So, we wanted to keep the alternative text but override the tooltip behaviour in Internet Explorer.

Setting an empty alt would have removed the tooltip, but at the expense of accessibility. That’s the obvious option out the window.

Before I go any farther, I thought I’d better point out that alt attributes are a good thing and are required for all images in markup. If you are reading this thinking otherwise, I highly recommend that you read up on appropriate use of alt attributes.

Another option was to add the image as a background with CSS, as it could have been considered a decorative image. Being so close to project finish, we didn’t want to have to go through the site making all the images backgrounds. We also wanted these images to stretch with increases in text size. Next option down.

Internet Explorer will correctly display the contents of a title attribute as a tooltip when one is set on an element. Rather conveniently, an empty title attribute overrides Internet Explorer’s ‘alt tooltip’ behaviour but does not show a tooltip. However, we can’t be sure this will happen in all browsers and I don’t like to muddy my markup.

We opted for an unobtrusive JavaScript solution. This keeps the solution in the behaviour layer and allows us to sniff out Internet Explorer.

Enter the JavaScript

I came up with two JavaScript solutions:

  1. Using mouse events for the image: when onMouseOver is triggered, swap out the existing alt text and set the alt to an empty string, then reinstate the original alt text when onMouseOut is triggered.
  2. Override the tooltip that appears as a result of the alt text by ensuring a title attribute is set on the image — an empty title attribute doesn’t display a tooltip in Internet Explorer, but does override the ‘alt tooltip’ behaviour for us.

The latter was preferential as it didn’t seem to have any immediately obvious accessibility issues.

A bit of a disclaimer: I don’t recommend overriding any behaviour unless you really have a need to do so. I used this solution in a selective manner. If you intend to use JavaScript to override behaviour in any significant way, consider providing client-side options so that users can set a preference.

So, without further ado, here’s the code I used. Feel free to use it, share it, suggest improvements or provide your insight on tooltips displaying alt text.

var objFixIeTooltip = {
	// methods
	init : function() {
		// detect support
		if (!document.getElementById || !document.getElementsByTagName) return;
		// detect IE - leave out if using conditional comments
		var isIE = navigator.userAgent.indexOf("MSIE");
		if (isIE < 1) return;
		// find the image(s) - tweak to your needs
		var elContainer=document.getElementById("header");
		if (!elContainer) return;
		var elImg=elContainer.getElementsByTagName("img")[0];
		if (!elImg) return;
		// if there isn't already a title attribute set on the image, set the title attribute to blank, thus overriding the alt tooltip behaviour
		// use == '' because IE always thinks title is a string (cannot distinguish between undefined and empty attributes)
		if (elImg.getAttribute('title') == '') elImg.setAttribute('title','');
	}
};
addLoadEvent(objFixIeTooltip.init);

Of course, to avoid using browser detection within the script, you could leave it out and include the script using conditional comments:

<!--[if IE]><script type="text/javascript" src="path/fixIEtooltip.js"></script><![endif]-->

References and reading

On alt tooltips:

On alt attributes and alternative text:

You can find more on alt attributes and alternative text in my del.icio.us bookmarks.

And just for fun – I love this: Wheee!