When testing a website or mobile application’s accessibility, some might say that someone who routinely uses a screen reader would be best placed to eke out issues, right? While it’s true that if you use a screen reader for everything you do on your computer, all the time, you naturally become an expert user over time, and you can find issues that may otherwise fly under the radar. Also, you tend to do certain tasks faster than an ad-hoc screen-reader user or tester would. But depending on the site or app under audit, full-time screen-reader users might not automatically be in a better position to spot issues.
In the worst-case scenario, when content is completely inaccessible, a totally blind auditor may not be able to process enough of what’s on the page to carry out any meaningful testing. Even auditing content that’s reasonably accessible has its challenges when you can’t see the screen to compare your understanding of the content with what’s visibly presented to the user.
I’m a blind accessibility engineer at TPGi, and I’ve been carrying out accessibility audits and tests in one form or another for almost 25 years. The landscape has changed beyond recognition since I began. In the first formal accessibility test that I carried out, I used Internet Explorer 3.0 and the JAWS 3.0 screen reader. The most common accessibility issues were images with missing or inadequate alternative text, form fields without labels, and text that looked like headings but wasn’t marked up as such. Accessibility testing wasn’t a complicated affair (and to be fair, the same old issues still present themselves to this day).
Fast forward to the days of custom widgets and frameworks, shadow DOM components, multiple ways to render images, and exponentially more complex testing scenarios. So what are the most serious blockers for blind testers, and are there ways to work around them? Below are just some of the issues I encounter that uniquely affect me as a blind tester.
Controls exposed as plain text
During testing, I frequently come across controls that look like links, buttons, checkboxes, and the like that don’t expose themselves as such to JAWS. Their function is usually to request details or confirmation from the user or to reveal extra information. Since they aren’t native interactive elements, they usually aren’t part of the tab order, and they don’t show up in JAWS’ forms list or links list. So they’re easy for a screen reader user to miss. Here is a classic example:
<p>We are experiencing high volumes of orders at the current time so wait times may be a bit longer. <span class="button">Learn More</span></p>
This looks like a button, but it’s not keyboard focusable. But the surrounding content and the class name provide some hints as to what the element is supposed to be.
The text labels assigned to these controls often give the game away. “Learn More” and “Full description” are labels that I assume must be disclosure widgets that would reveal extra information if I could just activate them, while “I am over 18” and “I agree to the terms and conditions” are most likely checkboxes that need to be checked before I can submit a form. So I activate the JAWS cursor, move it to the control and use JAWS to fire a click event on it. If more information appears, or if I’m suddenly able to submit a form, then happy days!
If not, I can always inspect the markup using Chrome’s or Firefox’s developer-tools panel, where I can traverse the DOM and look out for visually hidden
<input type="checkbox"> or
<input type="radio"> controls,
class="checkbox/radiobutton" attributes, or
<div> elements close to the element at hand that contain hidden content that might be exposed if the control was clicked. Failing that, I’ll check whether the element or one of its close neighbors has an attached click event. If none of these exist, I would have to revert to the old tried and trusted method of asking a colleague to check whether the element was interactive.
How it should be done
All interactive elements should expose their roles to screen readers and other assistive technologies, ideally by using native HTML elements such as
<a> elements for links,
<input type="checkbox">. It’s always better to use native controls where possible because keyboard functionality comes baked in. If for some reason native elements can’t be used, a role attribute should be added to the control, for example
States defined visually but not structurally
When undertaking a multistep process—such as creating a user profile or checking out an online shopping basket—the steps in the process are usually listed above the content, with the active step indicated in some way (such as a color change or bold text). But there’s often no structural way provided for a screen-reader user to know which step is the current one. Here’s a typical example:
<ol class="steps"> <li>Contact details</li> <li class="current">Payment details</li> <li>Authorize payment</li> </ol>
Visually it might look like this:
While ‘Payment details’ is not conveyed to JAWS to me as the current step, I do have a trick up my sleeve.
JAWS has two great features that I couldn’t do without during testing:
- Say Font (shortcut key JAWS key + F) describes the font: its name, font weight, text spacing and alignment.
- Say Color (JAWS key + 5) tells me the foreground and background colors of the character that the cursor is on.
So I can use JAWS to check the colors and font weight of an unselected item, and compare it with the same attributes of the item relating to the step that I deduce is currently active, which more often than not gives the game away. If this doesn’t tell me anything useful, I inspect the selected element’s markup in Chrome’s or Firefox’s developer-tools panel. And if it has a CSS class that’s different from that of unselected items, I’ll find the class in the CSS and work out what visual changes it makes. This all sounds very long-winded, but it doesn’t take long at all, and it often gives me insider knowledge when recommending a solution.
How it should be done
<ol id="steps"> <li>Contact details</li> <li aria-current="step">Payment details</li> <li>Authorize payment</li> </ol>
And here is a visual representation of the steps:
Note that in this revised example, the font isn’t set to bold anymore, but I don’t need to rely on JAWS’ font tools now—the current step is conveyed to me using the
aria-current attribute, and the step’s visual representation is no longer something that I need to rely on.
If I’m reporting on an accessibility issue I’ve discovered, it’s usually helpful for the developer if I can take a screenshot of the element and perhaps some surrounding content to provide some context. But how can a blind tester crop a screenshot to a specific area of the screen?
Bring on Firefox and its excellent Screenshot Node function. Developer tools panels are my friend, and Firefox often comes to the rescue here. If I inspect the element I’m interested in, Firefox has a function that can take a screenshot of only the selected node. If I need a bit more context, I can always take a screenshot of the parent node, which often provides the context I need.
If I’m not sure I’ve captured the right content, I’ll find the screenshot on my hard drive, then press JAWS key + Space, O, F to run a JAWS OCR scan on the screenshot and make sure it contains the content I want. This isn’t a perfect solution by any means, and there are times when I have to ask a colleague to take a more precise screenshot, to crop the one I’ve taken, or possibly to annotate or highlight a specific part of the image. But it means I can take most of the screenshots I need without input from anyone else. It’s a good feeling!
Tests that are problematic using a screen reader
There are a few very visual tests that just aren’t feasible for me to tackle. It wouldn’t be easy for someone who can’t see the screen to, for example, test whether content is cropped or overlapped at different screen sizes, resolutions and orientations. Taking a screenshot and running it through the JAWS OCR function can provide some insight into whether content that should be on the screen is missing or incomplete, but I can’t be precise enough to write up a robust description and recommendation of the problem.
I also tend to avoid issues involving colors, fonts and text spacing, as well as images containing complex content such as graphs, charts and diagrams. Where possible, I don’t test for keyboard focus either, because JAWS is very good at plugging gaps by, for example, adding elements to the tab order when they may have inadvertently been excluded by the developer.
Working with a colleague at TPGi, we created a spreadsheet listing all the WCAG 2.1 levels A and AA success criteria, and we split them into issues that I can reliably test for and those where I can’t provide reliable results (Word docx file). Between us, we worked out that I can test for around two thirds of the 2.1 success criteria. Naturally, in my ideal world, I would be able to carry out a complete audit, and I’ll continue to push boundaries and come up with solutions. But even I have my limitations.