The differing behaviors of screen readers across various browsers are noticed all the time by screen reader users, and differing levels of ARIA support are noticed in a similar manner, but the reasons why this happens aren’t commonly understood by the majority of people.
For example, the most widely used screen reader, JAWS, is hard coded to work best in Internet Explorer. The second most widely used screen reader, NVDA, is hard coded to work best in Firefox. This includes ARIA support.
Here is the reason why.
All browsers that support accessibility, include an Accessibility API that is built into the browser application. This includes Internet Explorer, Firefox, Chrome, and Safari in the Mac and iOS platforms.
The browser’s Accessibility API exposes public properties and methods that can be queried by third party applications, like screen readers, to retrieve information from the Document Object Model (DOM) within the browser, which is then conveyed to screen reader users. This is like a hand shaking procedure between the browser and the screen reader.
So, when you hear the word “link” when arrowing down the page for example, even though the word “link” is not actually on the page, the screen reader is conveying that the role of the current element is that of a link.
This happens, because the browser’s Accessibility API has exposed the role of the element in one of its public properties or methods, which the screen reader queries when it renders the page content in the Virtual Buffer. The screen reader sees that, in the browser’s opinion, the element is a link, so the screen reader reflects this element type in the Virtual Buffer.
This is true for all element types.
When I say “in the browser’s opinion”, I mean this literally, because it is possible to manually override what the browser’s Accessibility API returns for screen readers. This is where ARIA comes in.
So, when ARIA is added to a page, the browser detects the ARIA attribute, then it updates the information within its Accessibility API to reflect what the ARIA is supposed to convey.
The screen reader then queries the browser’s Accessibility API as usual, and renders the content in the Virtual Buffer using this updated information.
This is why, if you put role=”button” on a standard link like so:
<a role="button" href="#"> Some Link </a>
the browser’s Accessibility API will convey that this element is a button, and the screen reader will display the element as a button, which will appear in the Form Field list in JAWS as though it were a form field, and can be navigated to using the “b” and “shift+b” commands to jump between buttons on the page.
It’s important to understand this part, because ARIA only changes the information in the browser’s Accessibility API, and does not change the element in the browser itself. Within the browser, the above element is still a link, and appears as a link in the DOM, including all native handlers. The only difference, is that the browser’s Accessibility API portrays this element as a button for screen readers. Nothing else has changed.
This is why, if you put role=”button” on a Span tag, it will appear as a button for screen reader users, but it will still be a Span tag regardless.
Here is where the browser differences come in.
All browsers have different Accessibility APIs, which may have different public properties and methods, and may require different techniques for accessing the browser’s API and DOM. The same is true for ARIA support within each browser, since this needs to be added to each Accessibility API in a consistent manner across all browsers.
This is why a complex interactive component may work perfectly using JAWS and Internet Explorer, but not so well in Firefox or Chrome, or why the same component may work perfectly using NVDA in Firefox, but not so well in Internet Explorer or Chrome.
Here are some specifics.
In the Windows OS:
- The Accessibility API for Internet Explorer is implemented using MSAA and UIA.
- The Accessibility API for Firefox is implemented using MSAA and IAccessible2.
- The Accessibility API for Chrome is implemented using MSAA and IAccessible2.
In the Mac OS:
- The Accessibility API for Safari is implemented using Ax/uiA.
In the Linux OS:
- The Accessibility API is implemented using the Assistive Technology–Service Provider Interface (AT-SPI) and IAccessible2.
All of which include a mixture of shared and proprietary properties and methods that screen readers can tap into.
So what does this mean?
It means that, when programming complex interactive components according to the ARIA specification, differing levels of accessibility across various screen readers is unavoidable.
Here are a few examples of this, in one location for simplicity.
Now, all of the interactive components on the above page are specifically programmed according to the ARIA specification to ensure full compliance, and have been tested for full keyboard support.
In a perfect world, the keyboard accessibility would combine with the correct usage of ARIA and provide fully accessible user interface components for all screen reader users.
Unfortunately, in the world we live in, we can only do the best we can for as many people as possible instead.
For example, using JAWS 13 and Internet Explorer, you can navigate to the Calendar tab and press Enter or the Spacebar to activate it, then use Tab to navigate to the Calendar icon, and press Enter to activate the popup.
The calendar will open and the current date will be highlighted. You can then use the Left/Up/Right/Down arrow and Home/End keys to navigate the calendar grid cells, PageUp/PageDown to navigate by month, Alt+PageUp/PageDown to navigate by year, and press Enter to choose a particular date.
You can do the same thing using NVDA in Firefox with equal accessibility.
Now, if you try the same using JAWS 13 in Firefox instead, you will notice that the Virtual Cursor is not disabled when the popup opens as it was when using Internet Explorer, making it impossible to use the same key commands to navigate the calendar without first pressing Insert+Z to turn off the Virtual Cursor. The reason for this, is actually a bug in JAWS, where the role of ‘dialog’ is not being honored properly.
This shows an example of unequal support by screen readers within different browsers.
Similarly, when using JAWS13 in Internet Explorer to navigate and activate the tabs on the Bootstrap page, you were traversing an ARIA Tab control, which also includes ARIA standards compliant markup and cross browser keyboard event handling for keyboard only users.
This works equally well in both Internet Explorer and Firefox using both JAWS and NVDA.
Now, when you open the same page in Chrome using JAWS 13, then use the arrow keys to navigate from the top of the page to the bottom, you will notice that the ARIA Tabs are not properly announced. Instead, they are broken out onto separate lines, with repeating label text, and sometimes say “tab tab” with no label text at all. In contrast, the ARIA Tabs are announced correctly when using NVDA in Chrome.
When you open the Tree tab in Chrome using either NVDA or JAWS 13 however, then tab into the ARIA Tree control, and use the Left/Up/Right/Down arrow keys to navigate and expand branch nodes, you will notice that none of the branch nodes are announced as expandable, nor what the current state is, nor what the current level is, even though all of these things are announced correctly in both Internet Explorer and Firefox. This is happening because the hand shaking procedure between the browser (Chrome) and the screen readers (JAWS and NVDA) is not occurring properly, so this information is not announced as it should be, even though the component is programmed properly and in full accordance with the ARIA specification.
So, to conclude:
Programming accessible interactive components is not easy, and depending on the browsers and OSs that are used to test these components during development, accessibility results will vary between screen readers.
Therefore, the best way to ensure the highest level of accessibility for the highest percentage of screen reader users, is to program complex interactive components using the most widely used screen readers to test this functionality in the Operating Systems where they are most widely used.
Currently, this is within the Windows OS using JAWS and Internet Explorer, and using NVDA in Firefox for laptops and desktops. For mobile devices, the most widely used screen reader is Voiceover in iOS devices.
Lastly, here are a few important notes.
Interactive components should never be specifically programmed to work within specific AT/browser combinations, such as using ARIA hacks to make something work in Firefox and JAWS, when doing so results in non-standards compliant markup and inaccessible functionality elsewhere.
Cross browser scripting should always be used to ensure full keyboard accessibility without a screen reader running, which will work in all OSs.
When ARIA is used within HTML markup, it should only be used with strict adherence to the ARIA specification that the component type applies to. This will ensure that, when browsers that don’t currently support such components are updated according to the ARIA User Agent Specification, they will automatically start working properly when screen readers tap into this functionality. In the meantime, the majority of screen reader users will still be able to use these components accessibly.
- Looking for Object Inspector and other MSAA tools?: here
- 2012 WebAim Screen Reader Usage Survey:
- Why keyboard accessibility isn’t the same thing as screen reader accessibility: http://lnkd.in/jYnkZq
- Microsoft Active Accessibility (MSAA): http://en.wikipedia.org/wiki/Microsoft_Active_Accessibility
- Basic HTML5, ARIA, and Screen Readers: http://www.accessibleculture.org/research-files/ozewai2011/basic-html5-aria-screenreaders-presentation.html#(1)
- Brief history of browser accessibility support: http://www.paciellogroup.com/blog/2011/10/brief-history-of-browser-accessibility-support/
- ARIA Roles Model: http://www.w3.org/TR/wai-aria/roles
- ARIA User Agent Specification: http://www.w3.org/TR/wai-aria-implementation/