Hacks 67–76: Introduction

I have cared about accessibility for almost 13 years, ever since I worked at AT&T as a relay operator for the deaf and hearing impaired. My manager was deaf, and I learned enough American Sign Language to communicate with him in his native language. (He also read lips and spoke perfect English.) One of my co-workers, with whom I became close friends, had been blind since birth. He did the same job I did, using a device that converted the words on the screen to Braille characters. We often worked different shifts, but I learned enough Braille to write him letters, which he looked forward to reading when he came in to work the next day.

Accessibility isn't just wheelchair ramps and bigger bathroom stalls. It crosses all disciplines, it affects all workplaces, and it makes no exception for gender, race, ethnicity, or income. With more and more information being published online, with more and more vital online services being developed, web accessibility is more important than ever.

Tip

In the year 2004, an estimated 7.9% (plus or minus 0.2 percentage points) of civilian, noninstitutionalized men and women, aged 18 to 64 in the United States reported a work limitation. In other words, that's 14,152,000 out of 179,133,000 (or about 1 in 13) people. [1]

The hacks in this chapter are a compilation of accessibility-related scripts I've written and found online. Some of them are tools for web developers, to help them make their own pages more accessible. Some of them leverage the accessibility features already present on the Web. The last one [Hack #76] is a proof-of-concept I developed to showcase the power of Greasemonkey as an accessibility enablement technology.

Customizing the Web isn't just fun and games. For some people, it provides the only way to use the Web at all.

Highlight Images Without Alternate Text

Quickly see which of your images are missing the required alt attribute.

If you're a web developer, you should already know that web accessibility is important. One of the primary mechanisms for enabling blind and disabled users to view your pages is to provide alternate text for every image. This is so important that the alt attribute is actually a required attribute of every <img> element. Even spacer images need an explicit alt="" attribute to tell text-only browsers and screen readers to skip over the image when they display the page or read it aloud.

Validating your page with the W3C's HTML validator (http://validator.w3.org) will tell you if an <img> element is missing the required alt attribute, but it will also tell you every other single thing you did wrong. If you aren't coding exactly to the HTML specification, the really important errors (such as missing alt attributes) will get lost in a sea of arcane rules and trivial mistakes.

The Code

This user script will run on all pages by default, but you should probably modify the @include line to include just the pages you're currently developing. The bulk of the script logic is contained in the XPath query, "//img[not(@alt)]", which finds all <img> elements that do not include any alt attribute. It will not find images that contain a blank alt attribute, which is perfectly legitimate for spacer images used solely for page layout. It will also not find images whose alternate text is useless to blind users, such as alt="filename.gif" or alt="include alternate text here".

Running the Hack

After installing the user script (Tools → Install This User Script), go to http://www.amazon.com. You will see a number of images highlighted with a thick red border, as shown in Figure 8-1.

Figure 8-1. Inaccessible images highlighted on Amazon.com

This immediately highlights several accessibility problems on Amazon's home page. In the upper-left corner, they are cross-selling one of their new partner sites for buying gourmet food online. In the upper-right corner, they have an image link to a list of most wished-for items. Each of these images is missing the required alt attribute. In the absence of an alt attribute, screen readers will read the filename from the src attribute instead, which, as you can see, is completely meaningless.

Hacking the Hack

There are many different avenues to explore in highlighting broken images. You could expand the XPath query to find images with a blank alt attribute. These are legitimate for spacer images, but they should never occur on images that convey information (such as the "Shop in Gourmet Food" image in Figure 8-1):

You could also use a similar technique to find images that are missing other attributes, such as width and height. width and height attributes are not strictly required, but it helps browsers lay out the page more quickly if they know in advance how large an image will be:

Add an Access Bar with Keyboard Shortcuts

Display shortcut keys defined by a page.

An increasing number of sites define keyboard shortcuts, called access keys, for commonly used features. This is an accessibility aid for people who have difficulty using a mouse. For example, a site could define a shortcut to jump to the site's accessibility statement and another one to set focus to the site's search box (or jump to a separate search page). Unfortunately, there is no easy way to know which shortcuts the site has defined! This hack makes the keyboard shortcuts visible.

The Code

This user script runs on all pages. The code is divided into three parts:

Find all elements that define a keyboard shortcut with the accesskey attribute.

Loop through each of these elements and find the most logical label for the shortcut.

Add CSS styles to the page so the list of keyboard shortcuts appears in a fixed bar along the bottom of the browser window.

Step 2 is the hard part, because different HTML elements can define an accesskey attribute. Form elements like input, textarea, and select can each define an accesskey. The form element might or might not have an associated label that contains a text description of the form field. If so, the label might contain a title attribute that gives even more detailed information about the input field. If not, the label might simply contain text. Or the form field might have no associated label at all, in which case the value attribute of the input element is the best we can do.

On the other hand, the label itself can define the accesskey, instead of the input element the label describes. Again, we'll look for a description in the title attribute of the label element, but fall back to the text of the label if no title attribute is present.

A link can also define an accesskey attribute. If so, the link text is the obvious choice. But if the link has no text (for example, if it contains only an image), then the link's title attribute is the next place to look. If the link contains no text and no title, we fall back to the link's name attribute, and, failing that, the link's id attribute.

Running the Hack

After installing the user script (Tools → Install This User Script), go to http://diveintomark.org. At the bottom of the browser window, you will see a black bar displaying the keyboard shortcuts defined on the page, as shown in Figure 8-2.

Figure 8-2. Keyboard shortcuts defined on diveintomark.org

How you actually use the defined keyboard shortcuts varies by platform. On Windows and Linux, you press Alt along with the defined key. On Mac OS X, you press Command and the key. On http://www.diveintomark.org, you can press Alt-0 to jump to the site's accessibility statement, as shown in Figure 8-3.

Remove Conflicting Keyboard Shortcuts

"Add an Access Bar with Keyboard Shortcuts" [Hack #68] introduced the concept of site-specific keyboard shortcuts (called access keys, after the attribute used to define them). Like Greasemonkey itself, access keys can be used for good or for evil. A malicious web page could redefine all available access keys to point to a link that tries to download a harmful executable or pop up an advertising window. Or a web publisher could—with the best of intentions—end up defining access keys that conflict with standard keyboard shortcuts in your browser.

Wikipedia, an otherwise excellent online encyclopedia, is such a site. It defines several access keys, including some (such as Alt-E) that conflict with the keyboard shortcuts for opening menus in the Firefox menu bar. This hack removes all access keys from a page to avoid the possibility of such conflicts.

The Code

This user script runs on all pages. It uses an XPath expression to find all the elements with an accesskey attribute, and then removes the attribute. This is enough to get Firefox to remove the associated keyboard shortcut from the link or form field.

Running the Hack

This hack runs on all platforms, but it is especially useful on Microsoft Windows, where keyboard shortcuts to open menus conflict with keyboard shortcuts defined on the web page itself.

Before installing the user script, go to http://en.wikipedia.org/wiki/Music_of_Mongolia. Press Alt-E to try to open the Edit menu, or Alt-T to open the Tools menu. Holy conflicts, Batman! The web page has redefined Alt-E to jump to the editing page, and Alt-T to jump to the discussion page.

Now, install the user script (Tools → Install This User Script), and refresh http://en.wikipedia.org/wiki/Music_of_Mongolia. You can now press Alt-E to open the Edit menu, or Alt-T to open the Tools menu. All the standard key combinations work as you would expect them to.

Wikipedia is the highest-profile site that creates this problem (and it was the inspiration for this hack), but the possibility for conflict exists on any site. I leave this script installed with the default @include *, but if you use site-specific keyboard shortcuts, you can change the @include configuration to target only the sites that cause this problem.

Make Image alt Text Visible

In the HTML specifications, there are two attributes designed to allow text to be attached to an image: alt and title. The alt attribute is short for alternate, and it is designed to display when the image itself cannot. The title attribute is designed as an extra title to show when a user hovers his mouse over the image. Most browsers function this way. Microsoft's Internet Explorer, however, will treat an alt attribute as a title, and display it as a tool tip.(To be fair, Microsoft did this to emulate the broken behavior of Netscape 4.) As a result, many less-informed web site maintainers use alt as if it was made to display a tool tip. When using a compliant browser like Firefox, this information is inaccessible!

With the magic of Greasemonkey, though, we can resurrect this information. This hack makes all alt attributes for images appear as their tool tips, by assigning the text to the title attribute instead.

The Code

This user script runs on all pages. First, we execute an XPath query to find all the <img> and <area> elements; these are the elements usually assigned <alt> text where the author intended a <title>. Then, a simple for loop evaluates each element returned from the query. For each <img> or <area> that has an empty title attribute and a nonempty alt attribute, we copy the alt text into the title.

Running the Hack

Before installing this script, browse to any page that contains images with alt attributes, and they will be visible as tool tips when you hover your cursor over the image. For example, the Google home page uses an image with alt text, but no title. Pointing your mouse at the image does nothing, as shown in Figure 8-4.

Figure 8-4. Unmodified Google home page

Now install the script (Tools → Install This User Script) and refresh the Google home page. The alt text in the logo is revealed when you hover your mouse over the image, as shown in Figure 8-5.

Figure 8-5. Google home page with alt tool tips

Hacking the Hack

As shown in "Master XPath Expressions" [Hack #8], XPath is a language all its own. The logic used in the loop can be fit into a more complex XPath query:

I call this trading complexity. The overall code is not simpler; we've just moved the complexity from one part to another. The end result is the same, so it boils down to a matter of style.

—Anthony Lieuallen

Add a Table of Contents to Long Pages

Create a menu out of a page's header tags.

I read a lot of specifications online. Not as part of my day job; I mean I do this for fun. There are good specifications, and there are bad specifications, but there is one thing you can say about virtually all of them: they are incredibly long. And most of them are published online as a single HTML page. Firefox's incremental find feature helps when I'm trying to find something specific (just press Ctrl-F and start typing), but I still often get lost in the endless scrolling.

One nice thing about W3C specifications in particular is that they use HTML correctly. Section and subsection titles are marked up with header tags: <h1>, <h2>, <h3>, <h4>, and so on. This hack takes those header tags and creates an in-page table of contents. Using the same technique as "Add an Access Bar with Keyboard Shortcuts" [Hack #68], the script adds a fixed bar at the bottom of the browser window that contains a drop-down menu of all the headers on the page. Selecting a header from the menu jumps directly to that section on the page.

The Code

This user script runs on all pages. It iterates through all the <h1>, <h2>, <h3>, and <h4> elements on the page, and creates a <select> menu in a fixed-position bar along the bottom of the browser window, just above the status bar. Items in the menu are indented based on the header level, so when you drop down the menu, it appears to be a hierarchical table of contents. Finally, we add a Hide TOC button on the right side of the table of contents bar. Clicking Hide TOC hides the bar temporarily until you refresh the page or follow a link to another page.

Running the Hack

After installing the user script (Tools → Install This User Script), go to http://whatwg.org/specs/web-apps/current-work/. At the bottom of the browser window is a drop-down box labeled Table of Contents. Open the menu to see an outline of all the headers on the page, as shown in Figure 8-6.

Figure 8-6. Table of contents

You can select any of the headings in the menu to jump to that section on the page.

Use Real Headers on Google Web Search

Make Google's markup more semantic, and learn why it matters.

Google does an excellent job of indexing the Web, but it does a poor job of displaying the results. By poor, I mean not semantic. Why does semantic markup matter? Well, among other things, it enables hacks such as "Add a Table of Contents to Long Pages" [Hack #71] to extract meaningful information from the page.

It is also an accessibility issue. Screen readers for the blind have features that allow users to navigate a page by its header elements. Sighted users can simply glance at the page on screen and see how it's structured; screen readers can only "glance" at the page's markup. If a page uses poor markup, screen readers have a more difficult time determining how the page is structured, which makes it more difficult for blind users to navigate.

This hack changes Google search result pages to use reader header elements for each search result.

The Code

This user script runs on Google web search result pages. It uses hardcoded knowledge of Google's markup—each search result is wrapped in a <p class="g"> element—to wrap a real <h2> tag around the title of each result. It also adds an <h1>Search Results</h1> element at the top of the page. This <h1> is hidden from sighted users, but screen readers will still "see" it in the DOM and announce it to blind users.

Running the Hack

After installing the user script (Tools → Install This User Script), go to http://www.google.com and search for accessibility. The script does not appear to have made any difference, as shown in Figure 8-7.

Figure 8-7. Real headers?

This is because the script goes to great length to style the new <h2> elements so they look similar to the page's default text style. However, if you install autotoc.user.js[Hack #71], the difference becomes obvious, as shown in Figure 8-8.

Because the page now uses properly structured markup, the autotoc.user.js script can construct a table of contents for the page. This is essentially what screen readers do for blind users, by looking for real header elements and allowing the user to jump to the next or previous header.

Figure 8-8. Real headers!

Add a Toolbar to Zoom Images Easily

Reduce or enlarge individual images with a single click.

In Firefox, you can make any page text larger by pressing Ctrl-equals sign (=), or make it smaller by pressing Ctrl-hyphen (-).However, this does nothing to the images on the page. If you want to enlarge or reduce an image, you're out of luck.

Here's a cool little hack that adds a toolbar to each image on a page to make it larger or smaller.

The Code

This user script runs on all pages. It finds all the images on the page with the document.images collection, and then adds a toolbar of buttons (really, just a <div> with some <a> elements styled to look like buttons). Before you protest, I realize that this script isn't keyboard-accessible. You can't win them all.

Running the Hack

After installing this script (Tools → Install This User Script), go to http://www.oreilly.com. Hover your cursor over the tarsier logo in the top-left corner of the page to activate the zoom toolbar, as shown in Figure 8-9.

Figure 8-9. Image zoom toolbar

Click the plus (+) button to zoom in on the image, as shown in Figure 8-10.

Figure 8-10. Zoomed tarsier

You can also click the minus (–) button to reduce the image size, or click the ? button to restore the image to its original size.

Hacking the Hack

There are lots of interesting things to do with images besides zooming them. If you right-click on an image, Firefox gives you several choices: view the image in isolation, copy the image URL, save it to disk, and several others. We can't reproduce all of these functions in JavaScript, but we can do the first one: view the image in isolation.

Make Apache Directory Listing Prettier

Have you ever visited a page to find nothing but a plain list of files? If a folder has no default web page, the Apache web server autogenerates a directory listing with clickable filenames. Nothing fancy, but it works, so why complain? Because we can do better! This hack takes the raw data presented in Apache directory listings and replaces the entire page with a prettier, more accessible, more functional version.

The Code

This user script runs on all pages. Of course, not all pages are Apache directory listings, so the first thing the script does is check for some common signs that this page is a directory listing. Unfortunately, there is no foolproof way to tell; recent versions of Apache add a <meta> element in the <head> of the page to say that the page was autogenerated by Apache, but earlier versions of Apache did not do this. The script checks for three things:

The title of the page starts with "Index of /".

The body of the page contains a <pre> element. Apache uses this to display the plain directory listing.

The body of the page contains links with query parameters. Apache uses these for the column headers. Clicking a column header link re-sorts the directory listing by name, modification date, or size.

If all three of these conditions are met, the script assumes the page is an Apache directory listing, and proceeds to parse the preformatted text to extract the name, modification date, and size of each file. It constructs a table (using an actual <table> element—what a concept) and styles alternating rows with a light-gray background.

Now, install the user script (Tools → Install This User Script) and refresh http://diveintomark.org/projects/greasemonkey/. The user script replaces the plain directory listing with an enhanced version, which contains a real table with alternating rows shaded, as shown in Figure 8-14.

Figure 8-13. Plain Apache directory listing

When you hover over a file, the entire row is highlighted, as shown in Figure 8-15.

Also, when you hover over one of the column headers, you will see a tool tip explaining that you can click to sort the directory listing, as shown in Figure 8-16.

I've probably seen thousands of autogenerated directory listings, and it wasn't until I wrote this hack that I realized that you could click a column header to change the sort order. Usability matters!

Figure 8-14. Enhanced Apache directory listing

Figure 8-15. Row highlighting

Figure 8-16. Column sorting

Add a Text-Sizing Toolbar to Web Forms

Insert buttons before <textarea> elements to make the text larger or smaller.

I spend a lot of time—probably too much time—commenting on weblogs and web-based discussion forums. Despite several attempts to create some sort of universal commenting API, virtually all of these sites continue to use a simple web form with a <textarea> element for entering comments.

This hack alters web forms to add a toolbar above every <textarea> element. The toolbar lets you increase or decrease the text size of the <textarea>, without changing the style of the rest of the page. The buttons are fully keyboard-accessible; you can tab to them and press Enter instead of clicking them with your mouse.

Tip

I mention this up front, because accessibility matters, and also because it was harder than it sounds.

The Code

This user script runs on all pages. The code looks complicated, and it is complicated, but not for the reason you think. It looks complicated because of the large multiline gibberish-looking strings in the middle of it. Those are data: URIs, which look like hell but are easy to generate.(See "Embed Graphics in a User Script" [Hack #11] for more on data: URIs.)

The toolbar is displayed visually as a row of buttons, but each button is really just an image of something that looks pushable, wrapped in a link that executes one of our JavaScript functions. Since we'll be creating more than one button (this script has only two, but you could easily extend it with more functionality), I created a function to encapsulate all the button-making logic:

There are two things I want to point out here. First, I need to assign a bogus href attribute to the link; otherwise, Firefox would treat it as a named anchor and wouldn't add it to the tab index (i.e., you wouldn't be able to tab to it, making it inaccessible with the keyboard). Second, I'm setting the _target attribute to store a reference to the target <textarea>. This is perfectly legal in JavaScript; you can create new attributes on an object just by assigning them a value. I'll access the custom _target attribute later, in the onclick event handler.

If you read Mozilla's documentation on the Event object, you'll see that there are several target-related properties, including one simply called target. You might be tempted to use event.target to get a reference to the clicked link, but it behaves inconsistently. When the user tabs to the button and presses Enter, event.target is the link, but when the user clicks the button with the mouse, event.target is the image inside the link! In any case, event.currentTarget returns the link in all cases, so I use that.

Now the real fun begins. (And you thought you were having fun already!) I need to get the current dimensions and font size of the <textarea> so that I can make them bigger. Simply retrieving the appropriate attributes from textarea.style (textarea.style.width, textarea.style.height, and textarea.style.fontSize) will not work, because those only get set if the page actually defined them in a style attribute on the <textarea> itself. That's not what I want; I want the final style, after all stylesheets have been applied. For that, I need getComputedStyle:

Finally, do you remember that bogus href value I added to my button link to make sure it was keyboard-accessible? Well, it's now become an annoyance, because after Firefox finishes executing the onclick handler, it's going to try to follow that link. Since it points to a nonexistent anchor, Firefox is going to jump to the top of the page, regardless of where the button is. This is annoying, and to stop it, I need to call event.preventDefault() before finishing my onclick handler:

event.preventDefault();

All this was just for the sake of keyboard accessibility. What can I say? Some people build model airplanes. I build accessible web pages.

Type some text into the <textarea>, then click the first button (titled "Increase text size") to make the text and the <textarea> larger, as shown in Figure 8-18. Alternatively, while focus is in the <textarea>, you can press Shift-Tab twice to set focus to the Zoom In button, and then press Enter to activate the button.

Click the second button, titled "Decrease text size," to make the text smaller. Due to rounding, if you repeatedly zoom in and then repeatedly zoom out, the text and its surrounding box may end up a slightly different size. The zooming is not permanent, so you can refresh the page to return to the original size.

Figure 8-17. Zoom toolbar in web form

Figure 8-18. Zoomed web form

Make Google More Accessible for Low-Vision Users

Change Google's layout to make it easier for low-vision users to read.

As a class of disabilities, low-vision users are often ignored by accessibility experts. However, accessibility expert Joe Clark has recently published his research into the needs of web users with limited vision. He pioneered a technique known as the zoom layout: a special alternate style applied to a web page that specifically caters to low-vision users.

As I was learning about zoom layouts, it occurred to me that this would be a perfect application of Greasemonkey. (Actually, that thought occurs to me a lot these days.) This hack is my first attempt at transforming a site into a zoom layout.

This hack is written to be cross-browser compatible. It works in Firefox with Greasemonkey, in Internet Explorer 6 for Windows with Turnabout, and in Opera 8 with its built-in support for User JavaScript. You can download Turnabout at http://reifysoft.com/turnabout.php, and Opera at http://www.opera.com.

Running the Hack

After installing the user script (Tools → Install This User Script), go to http://www.google.com. The normally spartan search form has been magnified and simplified even further, as shown in Figure 8-19.

Accessibility studies have shown that low-vision users have an easier time reading light text on a dark background, so therefore the page is displayed as white-on-navy. Unvisited links are displayed in yellow; visited links are displayed in light green. The hack removes several elements from the page, including the Advanced Search link, plus any advertisements for Google services or other messages that occasionally appear below the search box.

Figure 8-19. Google home page, zoomed

When you execute a search, the search results are displayed differently, as shown in Figures 8-20 and 8-21, with the following notable differences:

The entire page uses the same white-on-navy color scheme we used on the home page.

The Google logo in the top-left corner is displayed as plain text instead of as an image.

The top search form no longer includes the Advanced Search option.

The sponsored links along the top and right are gone.

The number of results is displayed much larger than before, and in the same white-on-navy color scheme.

Links to search results pages are displayed in yellow (or green, if you've already visited that page). Other links within each search result, such as the "Cached" and "Similar pages" links, are displayed in white.

The "Goooooooogle" navigation bar to see more results is replaced by a simple link titled "More results."

The search box at the bottom of the page is gone.

Figure 8-20. Google search results, zoomed

Figure 8-21. Bottom of Google search results, zoomed

If you click the Images link at the top of the page to search for the same keywords in Google Image Search, you will see that the image search results have been similarly hacked, as shown in Figure 8-22.

Figure 8-22. Google image results, zoomed

As with the web search results, the top navigation has been simplified, the number of results is more prominent, and the "Goooooooogle" navigation bar has been replaced by a single "More results" link that moves to the next page of images. The image thumbnails themselves cannot be magnified, since Google provides them only in a specific size.

Notes

↑ Houtenville, Andrew J. "Disability Statistics in the United States." Ithaca, NY: Cornell University Rehabilitation Research and Training Center on Disability Demographics and Statistics (StatsRRTC), http://www.disabilitystatistics.org, April 4, 2005.