Archive: April, 2008

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.

Assistive technology videos updated with more from YouTube

Mac snippet solution: Quicksilver Shelf

I’ve been looking around for something that I can store little bits of text in and then easily grab them when I need them. There are a few note-taking solutions for Mac out there that would suit, but I tend to use TextMate for notes – its templates and snippets are great for the majority of what I do – fairly big chunks of predefined text. Then I stumbled across an item on Lifehacker about Quicksilver’s Shelf. I use Quicksilver for other things anyway, so I gave it a whirl.

Using Quicksilver’s Shelf

Quicksilver’s Shelf is fairly basic for text, but it suits my needs fine. To use it, you’ll need to make sure the Shelf is installed.

The notes below will guide you through setting up the Shelf. If you’d prefer a visual guide, Sherwin Techico has recorded a useful screencast showing you how to set things up.

  1. Open up Quicksilver’s plug-ins preferences and find the Shelf Module under All Plug-ins.
  2. Make sure the box next to it is ticked.
  1. Once it is installed, you may need to restart Quicksilver.

To save an item to the Shelf:

  1. Invoke Quicksilver (I use Control+Space Bar).
  2. Press the . key (period) to enter Quicksilver’s text mode.
  3. Type or paste in some text that you want to save on the Shelf.
  4. Hit the Tab key and as you begin to type “shelf” you should see the “Put on Shelf” action come up.
  1. Hit Enter and your text is saved.

To recall items from the Shelf:

  1. Invoke Quicksilver.
  2. Type “shelf” and you should see the Shelf item appear – not the Shelf & Clipboard (Catalog) entry.
  3. Press the Right Arrow key to see the items on your Shelf.
  4. Press the Tab key to select an action. for some reason Large Type tends to be the default, but as you begin to type “copy” you should see the “Copy to Clipboard” action appear.
  1. Hit Enter and the item is in your clipboard ready to be pasted out.

If you’re a Quicksilver freak, it’s definitely worth checking out some of the Shelf’s other capabilities though. Check out the item on Lifehacker about Quicksilver’s Shelf for more on that.

Deleting Quicksilver Shelf items

The one thing that I really needed to do as I was testing it out was to delete a Shelf item once I’d put it in. There’s no option to delete a Shelf item in the command window or the catalog. According to one source, you used to be able to drag your saved Shelf items off to Trash. Nope, don’t work for me. Actually, if you invoke Quicksilver, bring up the Shelf, hit Tab and select the “Open” action, the Shelf window will pop open. You can drag items from this Shelf window to Trash.

Update: Thanks to a comment from Michael, I now know that the easier way to bring up the Shelf window is by invoking Quicksilver and then using Command+Option+S. From there you can select the item you want to delete and then hit Delete or Backspace.

Code monkeys will be fine with this approach though: Find your Quicksilver Shelves in your home directory, typically in /Users/[you]/Library/Application Support/Quicksilver/Shelves. Open up the Shelf file in your favourite text editor and remove the offending dict item from the XML.

Get more from the Shelf

I might be wrong, but I get the feeling the Shelf feature has been neglected of late. It seems you used to be able to dock the Shelf to the side of your screen, which might be useful, but I can’t get that to work in the latest version. Mind you, I’m quite happy invoking Quicksilver whenever I need something.

One thing you can do to help is set up a custom trigger (keyboard shortcut) that opens up the Shelf window. To do this:

  1. Open up the Triggers preferences in Quicksilver.
  2. Hit the plus icon at the bottom to add a new trigger; select HotKey.
  3. Bring Shelf up by typing “shelf” in the “Select an item” box.
  4. In the “Action” box, select Show by typing “show”.
  5. Save that and then double click on the HotKey symbol to the right to edit the action’s keyboard shortcut.
  6. Select the “Edit” button and set your chosen shortcut; I use Control+Option+Command+Space Bar.
  1. You can then close the window and try it out.

John Slatin Fund Accessibility Project

John Slatin was a leading light in the field of web accessibility, which is a passion of mine and my area of work. He co-authored Maximum Accessibility – a book on web accessibility – was co-chair of the WCAG Working Group for a time and led accessibility research at the University of Texas at Austin. Sadly, John passed away in March after a three-year battle with leukaemia.

I never met John, but along with many other accessibility experts, I’m taking part in the John Slatin Fund Accessibility Project to help raise money for John’s wife, Anna, to honour John and to promote his cause; accessibility.

The project aims to raise money to help his family with the medical expenses incurred during John’s illness. Volunteer accessibility experts are matched to companies that want to have their web site checked over for accessibility issues. In return for a brief accessibility audit, the web site owners contribute a minimum of $500 to the John Slatin Fund.

More than 70 accessibility experts have volunteered their time to the project; now we’re looking for companies to take part too. If you work for or know of a company that would be interested in taking part, please point the appropriate people to the project information for companies or contact me directly.

Character references: widening screen readers’ eyes

I ran some tests a couple of years ago that looked at how mathematical character references are handled by screen readers, specifically using default configuration in JAWS and Window-Eyes.

Jason Kiss of Accessible Culture has recently published a comprehensive set of results from his testing of how a variety of characters are dealt with by recent versions of JAWS and Window-Eyes: JAWS, Window-Eyes and Character References.

Analysis

A web author may expect characters such as the minus sign – a proper − or − as opposed to a simple dash – would be read out in an appropriate way by a screen reader. However, the most prevalent screen reader, JAWS, does not announce the character and the next most popular screen reader, Window-Eyes, reads it as “dash”.

Using JAWS, the results seem to be consistent even when you change the verbosity level, the punctuation level or the synthesiser used. It’d be interesting to know if anyone has managed to get a screen reader to announce these characters using the more advanced settings.

Personally, I’d like to see (or hear!) screen readers announcing additional characters; it would add to the character palette we can draw from when writing content, which I would expect to be even more important as the Web embraces internationalisation and localisation.

In the meantime, Jason provides a convenient table of results comparing the speech output from JAWS and Window-Eyes.

Update: Having posted about Jason’s work on Accessify Forum, I thought I’d add that some characters that do get spoken are not announced as one might expect:

  • Both JAWS and Window-Eyes read a square root symbol (√) as the letter v and pi (π) as the letter p.
  • While Window-Eyes makes minor tweaks to its speech output to make it a bit more user-friendly, it doesn’t always do what I think it should. As mentioned above, it says “dash” for the proper minus sign character.
  • Window-Eyes announces quite a lot of characters as “question”. Presumably Window-Eyes hasn’t understood these characters so it is announcing the character as it would a question mark, which users may realise it means that Window-Eyes hasn’t understood. However, saying “question” is probably worse than simply not announcing anything at all.

Happy JavaScript Amputation Day!

I’ve been coerced into stripping off in aid of CSS Naked Day for another year, but I’ve also changed my behaviour.

What’s CSS Naked Day all about?

The idea behind this event is to promote Web Standards. Plain and simple. This includes proper use of (x)html, semantic markup, a good hierarchy structure, and of course, a good ‘ol [sic] play on words. It’s time to show off your <body>.

It’s a nice way to exploit the viral nature of the Web to promote web standards and good design, and it works well because it has visual impact. The huge number of CSS design galleries are testament to the fact that the Web grew up to be a place to show off talent for visual design.

Where next for viral evangelism in web standards?

When it comes to separation of CSS and JavaScript from our plain old semantic HTML, CSS Naked Day has it covered. What about raising awareness of using progressive enhancement to implement JavaScript features? In a time when the Web is an application playground fuelled by Ajax, I’d like to see people paying more attention to making sites work both with and without JavaScript.

So, today I’m removing not just my CSS styles, but my JavaScript as well. Perhaps you’d like to do the same?

del.icio.us proxy v1.1 update