Introduction
WAI-ARIA is one of the best
things ever to happen to web accessibility. It paved the way to free us
from a world where JavaScript and any widget that didn’t have an HTML
tag equated to inaccessibility. Aside from it being deployed by authors,
I’ve even managed to majorly improve the accessibility of various websites using Greasemonkey scripts. I love ARIA.
But sometimes, I hate ARIA. Yes, you heard me. I said it. Sometimes, it drives me truly insane.
Let’s take aria-label and aria-labelledby. They’re awesome. Authors can
just use them to make screen readers speak the right thing. Simple,
right?
Not at all. I wish it were that simple, but it is so, so much more complicated than that. I’ve had a ridiculous number of discussions/arguments about aria-label/aria-labelledby over the years.
Frankly, when I hear about aria-label/ledby, it just makes me cringe
and groan and, depending on the day, consider quitting my job. (Okay,
perhaps that last part is a bit melodramatic.)
The most frustrating part is that people frequently argue that assistive
technology products aren’t following the spec when their particular use
case doesn’t work as expected. Others bemoan the lack of
interoperability between AT products and often blame the AT vendors. But
actually, the ARIA spec and guidelines don’t say (not even in terms of
recommendations) anything about what ATs should do. They talk only about
what browsers should expose, and herein begins a great deal of
misunderstanding, argument and confusion. And when we do try to fix one
seemingly obvious use case, we often break another seemingly obvious use
case.
In this epic ramble, I’ll attempt to explain just how complicated this
supeficially trivial issue is, primarily so I can avoid having this
argument over and over and over again. While this is specifically
related to aria-label/aria-labelledby, it’s worth noting there are
similar cans of worms lurking in many other aspects of ARIA. Also, I
specifically discuss screen readers with a focus on NVDA in particular,
but some of this should still be relevant to other AT.
Why not just use the accessible name?
Essentially, aria-label/ledby alters what a browser exposes as the
“name” of an element via accessibility APIs. Furthermore, ARIA specifies
when the name should be calculated from the “text” of descendant
elements. So before we even get into aria-label/ledby, let’s address the
question: why don’t screen raeders just use the name wherever it is
present?
The major problem with this is that the “name” is just text. It doesn’t provide any semantic or formatting information.
Take this example:
<a href="foo"><em>bar</em> bas</a>
A browser will expose “bar bas” as the name of the link exactly as you
might expect. But that “bar bas” is just text. What about the fact that
“bar” was emphasised? If we just take the name, that information is
lost. In this example:
<a href="foo"><img src="bar.png" alt="bar"> bas</a>
the name is again “bar bas”. But if we just take the name, the fact that “bar” is a graphic is lost.
These are overly simple, contrived examples, but imagine how this begins to matter once you have more complex content.
In short, content is more than just the name.
Just use it when aria-label/ledby is present.
Okay. So we can’t always use the name. But if aria-label/ledby is present, then we can use the name, right?
Wrong. To disprove this, all we have to do is take a landmark:
<div role="navigation" aria-label="Main">Lots of navigation links here</div>
Now, our screen reader comes along looking for content and sees there’s a
name, which it happily uses as the content for the entire element.
Oops. All of our navigation links just disappeared. All we have left is
“Main”. (Of course, no screen reader actually does or has ever done this as far as I'm aware.)
That’s just silly. You obviously don’t do it for landmarks!
Well, sure, but this raises the question: when do we use it and when
don’t we? “Common sense” isn’t sufficient for people, let alone
computers. We need clear, unambiguous rules. There is no document which
provides any such guidance for AT, so each product has to try to come up
with its own rules. And thus, the cracks in the mythical utopia of
interoperability begin to emerge.
That really sucks. But enough doom and gloom. Let’s try to come up with some rules here.
Render aria-label/ledby before the real content?
Yup, this would fix the landmark case. It is bad for a case like this, though:
<button aria-label="Close">X</button>
That “X” is meaningless semantically, so the author thoughtfully used
aria-label. If we use both the name and content, we’ll get “Close X”.
Yuck!
Landmarks are just special. You can still use aria-label/ledby as content for everything else.
Not so much. Consider this tweet-like example:
<li tabindex="-1" aria-labelledby="user message time">
<a id="user" href="alice">@Alice</a>
<a id="time" href="6min">6 minutes ago</a>
<span id="message">Wow. This blog is horrible: <a href="http://blog.jantrid.net/">http://blog.jantrid.net/</a></span>
<a href="conv">View conversation</a>
<button>Reply</button>
</li>
Twitter.com uses this technique, though the code is obviously nothing
like this. The “li” element is the tweet. It’s focusable and you can
move between tweets by pressing j and k. The aria-labelledby means you
get a nice, efficient summary experience when navigating between tweets;
e.g. the time gets read last, the View conversation and Reply controls
are excluded, etc. But if we used the name as content, we’d lose the
formatting, links in the message, and the View conversation and Reply
controls. If we render the name before the content, we end up with
serious duplication.
Can I at least label links and buttons?
Believe it or not, I actually have good news this time: yes, you can.
But why links and buttons? And what else falls into this category? We
need a proper rule here, remember.
There are certain elements such as links, buttons, graphics, headings,
tabs and menu items where the content is always what makes sense as the
label. While it isn’t clear that it can be used for this determination,
the ARIA spec includes a characteristic of “Name From: contents”
which neatly categorises these controls.
Thus, we reach our first solid rule: if the ARIA characteristic “Name From: contents” applies, aria-label/ledby should completely override
the content.
What about check boxes and radio buttons?
Check boxes and radio buttons don’t quite fit this rule. The problem is
that the label is often (but not always) presented separately from the
check box element itself, as is the case with the standard HTML input
tag:
<input id="Cheese" type="checkbox"><label for="cheese">Cheese</label>
The equivalent using ARIA would be:
<div role="checkbox" aria-labelledby="cheeseLabel"> </div><div id="cheeseLabel">Cheese</div>
In most cases, a screen reader will see both the check box and label
elements separately. If we say the name should always be rendered for
check boxes, we’ll end up with double cheese: the first instance will be
the name of the check box, with the second being the label element
itself. Duplication is evil, primarily because it causes excessive
verbosity.
Okay, so we choose one of them. But which one?
Ignore the label element, obviously. Duh.
Perhaps. In fact, WebKit and derivatives choose to strip out the label
element altogether as far as accessibility is concerned in some cases.
But what about the formatting and other semantic info?
Let’s try this example in Google Chrome, which has its roots in WebKit:
<input type="checkbox" id="agree"><label for="agree">I agree to the <a href="terms">terms and conditions</a></label>
The label element gets stripped out, leaving a check box and a link. If I read this in NVDA browse mode, I get:
check box not checked, I agree to the terms and conditions, link, Terms and conditions
Ug. That’s horrible. In contrast, this is what we get in Firefox (where the label isn’t stripped):
check box not checked, I agree to the, link, Terms and conditions
Ignoring the label element means we also lose its original position
relative to other content. Particularly in tables, this can be really
important, since the position of the label in the table might very much
help you to understand the structure of the form or aid in navigation of
the table.
Fine. So use the label element and ignore the name of the check box.
Great. You just broke this example:
<div role="checkbox" aria-label="Muahahaha"> </div>
Make up your mind!
I know, right? The problem is that both of these suck.
The solution I eventually implemented in NVDA is that for check boxes and
radio buttons, if the label is invisible, we do render the name as the
content for the check box. Finally, another solid rule.
Sweet! And this applies to other form controls too, yeah?
Alas, no. The trouble with other form controls like text boxes, list
boxes, combo boxes, sliders, etc. is that their label could never be
considered their “content”. Their content is the actual stuff entered
into the control; e.g. the text typed into a text box.
If the label is visible, it’s easy: we render the label element and
ignore the name of the control. If it isn’t visible, currently, NVDA
browse mode doesn’t present it at all.
To solve this, we need to present the label separately. For a flat
document representation such as NVDA browse mode, this is tricky, since
the label isn’t the “content” of anything. I think the best solution for
NVDA here is to present the name of the control as meta information,
but only if the label isn’t visible. I haven’t yet implemented this.
Rocking. Can the label override the content for divs, spans and table cells?
No, because if it did, again, we’d lose formatting and semantic info.
These elements in particular can contain just about any amount of
anything. Do we really want to risk losing that much formatting/info?
See the Twitter example above for just a taste of what we might lose.
Another problem with this is the title attribute. Remember I mentioned
that aria-label/ledby just alters what the browser exposes as the
“name”? The problem is that other things can be exposed as the name,
too. If there is no other name, the title attribute will be used if
present. I’d say it’s quite likely that the title attribute has been
used on quite a lot of divs and spans in the wild, perhaps even table
cells. If we replaced the content in this case, that would be… rather
unfortunate.
Some have argued that for table cells, we should at least append the aria-label/ledby.
Aside from the nasty duplication that might result, this raises a new
category of use cases: those where the label should be appended to the
content, not overide it. With a new category begin the same questions:
what are the rules for this category? And would this make sense for all
use cases? It certainly seems sketchy to me, and sketchy just isn’t okay
here. Again, we need solid, unambiguous rules.
Stop! Stop! I just can’t take it any more!
Yeah, I hear you. Welcome to my pain! But seriously, I hope this has
given some insight into why this stuff is so complicated. It seems so
simple when you consider a few use cases, but that simplicity starts to
fall apart once you dig a little deeper. Trying to produce “common
sense” behaviour for the multitude of use cases becomes extremely
difficult, if not downright impossible.
If we want interoperability, we need solid rules. I’m not necessarily
suggesting that this be compulsory or prescriptive; different AT
products have different interaction models and we also need to allow for
preferences and innovation. Right now, though, there’s absolutely
nothing.
Hi james, thanks very much for documenting. I have started compileing doc/test files suggesting what screen readers should announce from accname/description info. http://thepaciellogroup.github.io/AT-browser-tests/AT.html bugs and PR' welcome!
ReplyDeleteWow, Steve! Responsive or what? :) Thanks for the start.
DeleteI'll certainly follow up with issues/PRs, but I thought I'd mentino this here because it's somewhat more general.
For a with href, you write:
> Announce accname + accdescription (if present and different from acc name), ignore element content.
There are two problems i see here:
1. We don't want to ignore the element content if the name doesn't actually override it; i.e. if it came from descendants. See the "Why not just use the accessible name?" section of my article for why; in short, we lose formatting/semantic info.
2. IMO, description is secondary content and shouldn't always be read for efficiency reasons. I think I need to write another blog post for this one.
Hi James, the advice a added was just as an example, to stimulate discussion, i guess what I am trying to achieve is to get a sense if this type of concept is useful, worth prusuing. So yes please do feedback/PR
DeleteHi again James, I have conducted some testing for links, using the output i suggested. I think the results are both interesting and disconcerting http://thepaciellogroup.github.io/AT-browser-tests/acc-name-test/a-href.html
DeleteGood points James. The problem we have with AT vendors is that many have lobbied very hard for us to NOT dictate what they should do. The ARIA working group shares your frustration. This problem extends beyond ARIA. The new 508 rewrite says nothing about AT requirements as they successfully lobbied the TEITAC community to NOT place any user interface requirements on them.
ReplyDeleteAll this said, I think we could look at some best practices for AT in the future but that would require their participation.
Thanks for commenting, Rich.
DeleteI think there are good reasons not to be too strict in dictating what AT should do. As I said, there needs to be room for different interaction models, innovation, etc. It's a very fine line, though. I think the current situation (nothing) is too little, but the other extreme would also be bad.
This comment has been removed by the author.
ReplyDeleteThanks James...
ReplyDeleteThe most common mistake I'm correcting for aria-label/ledby is when it over rides the text in the element, or associated label and when that text or associated html label is important. For instance, a bit of help text on an input. They should use describedby but they don't understand the difference between accName and accDescription.
Regarding your example, for container elements such as groupings and landmarks, etc. the accessible name should not suppress access to the content itself. I've actually seen this occur in some mobile screen readers!
ReplyDeleteI agree for composite controls like combo boxes we need a better way to communicate the current value/selected child and the accessible name -- I don't think enough thought was put into how the value or selected child would be exposed. In MSAA it was exposed as the accessible value or was picked up by looking for the selected child element.
I hear you on the point of losing semantic information when a label is translated into a flat string. For example, some checkboxes have labels that contain links and you might want to know that information when hearing the label. This is something that should be considered. But generally I would like to see assistive technology follow the rules defined by the name calculation and associated documents for describing as we rely on consistency in guiding customers to remediate their code.
Thanks for your comments, Jonathan.
Delete> Regarding your example, for container elements such as groupings and landmarks, etc. the accessible name should not suppress access to the content itself.
Indeed, as I noted in the "That’s just silly. You obviously don’t do it for landmarks!" section of my post. My point in raising that example was that the behaviour that most people propose (replacing the content with the label) is absolutely not what we want, and if that simple example breaks the rule, a plethora of others would, too.
> generally I would like to see assistive technology follow the rules defined by the name calculation and associated documents for describing as we rely on consistency in guiding customers to remediate their code.
Unfortunately, as I've pointed out in my post, there are just too many use cases where following these "rules" (and they aren't rules for AT anyway; see the second last paragraph of my Introduction) doesn't produce the "expected"/intuitive behaviour for some use case or another. We need more specific rules if we want interoperability (see the final section of my post).
You lost me as soon as you started calling it "name". Name? No, not even close.
ReplyDeleteOn the contrary, aria-label/ledby maps to "name" in most accessibility APIs. You'll also note that ARIA uses the term "accessible name computation". This has nothing to do with the HTML "name" attribute, though.
DeleteNot a complete solution, just thinking out loud...
ReplyDeleteDo we need some way to explicitly spit the two behaviours? maybe one to only label the thing (keeping/prefixing its content), and one to replace the content?
Maybe aria-label to give the thing a name/label (e.g. landmarks), and a new attribute like aria-content or aria-contentby, to replace its content with something else (e.g. the Twitter example).
This does not address form fields/labels though.
WebbIE is rotten with rules like this. IF aria-hidden AND Not An Audio Element THEN hide. Ignore the hidden attribute for the BODY element. And so on. But we stagger on, trying to decide if Facebook is big enough to special-case (probably) but the BBC not (probably)...
ReplyDeletePositive site, where did u come up with the information on this posting? I'm pleased I discovered it though, ill be checking back soon to find out what additional posts you include. Search Bar Firefox 57 Quantum addon
ReplyDeleteBss commerce
ReplyDeleteGREAT POST