I am trying to optimize a few components for screen readers, however Android Talkback proves to be a challenge....
Here is a very simplified example for the code:
<div class="wrapper">
<form>
<span role="presentation" aria-hidden="true">
This should not be read by Talkback
</span>
<input aria-label="This should be read by Talkback" />
</form>
</div>
The text inside the span is updated dynamically, and is positioned absolutely over the input - just to appear like an animated placeholder, without actually being read by screen readers. That is what the aria-label is for. However, TalkBack still seems to recognize the span - so it reads the content of the aria-label first, then continues reading the text in the span... role "presentation" or role "none" did not prevent this, neither did moving the text even further from the input. (For example, outside the form). Is there any way to prevent this?
The role attribute only changes the type of element that Talkback and other screen readers announce. Setting it to presentation or none just removes the semantic type of element. A <span> does not have a native role by default so it's essentially presentation/none implicitly and won't have any effect.
aria-hidden is the key. It will hide the element from the screen reader. (CSS display:none and visibility:hidden will also hide an element from the screen reader but it also makes the element invisible to sighted users too.)
Your code example should work just fine with Talkback. However, you mentioned that you dynamically change the contents of the <span>. That's not a problem but is there a chance that when you updated the text, the aria-hidden got removed?
I have used aria-hidden on Android without any trouble.
The solution in my example was already enough to fix the issue.
aria-hidden prevents the span being focusable, and if the span is located before (and not after), TalkBack will not interpret the text as being part of the input.
Related
Which is the correct way to make inline tooltips accessible?
I have 2 versions below.
Version 1: Use the title attribute. When hovering I will use JS to hide the title attribute and add the text to my custom tooltip. I will add back the title attribute when hover is off.
<p>For here am I sitting in a <span title="A spaceship">tin can</span> far above the world planet earth...</p>
Version 2: use aria=label and role="tootlip"
<p>For here am I sitting in a <span aria-label="A spaceship" role="tooltip">tin can</span> far above the world planet earth...</p>
Note: this question is for inline tooltips only, meaning the tooltip text is in the attribute of the element which triggers the tooltip. The tooltip is not separate from the element triggering it.
The title attribute by itself does not reliably provide an accessible name for the element, meaning it will not be read by all screen readers.
Aria-label has no function if it is not assigned to an interactive element. Beware also, that the aria-label replaces the element’s content from an accessibility perspective.
Since you want to use that attribute only to inject another element with that text as its content, the issue here is more one of confusion, and it might be better to use a non-semantic attribute in that case like data-tooltip.
The aria-label attribute defines a string value that labels an interactive element.
Which brings us to another aspect: The tooltip needs to work with touch screens and keyboard, too. So it will need to be focusable and focus needs to be visible. A tooltip should also be closable by means of Esc.
A tooltip is a popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it. It typically appears after a small delay and disappears when Escape is pressed or on mouse out.
https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/
Since aria-describedby is recommended for screen readers to reference the additional contents, it is better to have that element already in the DOM, which would simply be hidden or shown depending on tooltip state.
<p>For here am I sitting in a <span aria-describedby="tooltip-spaceship" tabindex="0" role="tooltip">tin can</span> far above the world planet earth...
<span id="tooltip-spaceship" hidden>A spaceship</span></p>
Lastly, the least expensive way, which is easier to use as well, is to simply provide them in the text at their first occurrence:
<p>For here am I sitting in a <dfn>tin can</dfn> (a spaceship) far above the world planet earth…</p>
See also Understanding Success Criterion 3.1.3: Unusual Words
I want to replace some third party generated content using pure CSS. There are various techniques covered by other questions but the basic idea is hide the exiting content and add new content with pseudo selectors.
I'm interested in whether this is an acceptable thing to do from an accessibility point of view. Would a screen reader see both bits of text or only the original? Should the CSS be wrapped in #media screen {} to avoid both being used?
In my situation I can only use CSS. I can't edit the HTML or use any JavaScript. Is there any way to present only the replacement text to a screen reader?
.third-party-content {
font-size:0;
}
.third-party-content:before {
content:"lovely replacement";
font-size:initial;
}
<div class="third-party-content">unwanted garbage</div>
Don't use CSS generated text to convey meaningful information at all.
Screen readers don't behave the same. Some of them always read it, some of them never, and some of them sometimes do or don't depending on other properties.
For example, NVDA reads CSS generated text most of the time; Jaws rarely does (if ever it does sometimes).
Anyway, according to the base separation principle: content/structure=HTML, behavior/action=JavaScript, appearance=CSS, it isn't semantically correct to let CSS generate meaningful text.
It should be done in HTML. In fact the CSS Content propertiy should never be used for something else than text icons and other pure visual things that don't really matter for general understanding if they are skipped / not shown / not read.
Changing the font-size to 0 just changes the visual appearance of the text but does not hide it from a screen reader. A screen reader does not care what size the font is. It's just text that will be read.
When a screen reader reads text, it's called the "accessible name". The accessible name is computed according to these rules - https://www.w3.org/TR/accname-1.1/#step2. In particular, see step 2.F.ii
"ii. Check for CSS generated textual content associated with the current node and include it in the accumulated text. The CSS :before and :after pseudo elements can provide textual content for elements that have a content model."
One way to hide text from a screen reader is to use the aria-hidden attribute but that would require changing the HTML, which you stated you can't do. Text is also hidden using standard display:none, but that would obviously hide your :before text too.
Using CSS tricks to visually hide text, such as clip, position, width, etc, again just visually hides the text but does not hide it from a screen reader.
I'm not a CSS expert but building on your attempted solution of font-size, I added visibility:hidden and it seemed to work. I know hidden just makes the text invisible but still takes up space on the screen, but when combined with your font-size:0 (and inherit) it prevents the "unwanted garbage" from taking up any space so if you had an element adjacent to your original, you wouldn't have a big gap between the two.
visibility:hidden does hide the element from the screen reader.
.third-party-content {
font-size:0;
visibility:hidden;
}
.third-party-content:before {
content:"lovely replacement";
font-size:initial;
visibility:initial;
}
You cannot use display:none in a similar solution because as soon as the parent is hidden, the :before is hidden too.
Update: This solution works with NVDA (screen reader) on firefox and VoiceOver on iOS. (Chrome with screen readers is typically not tested because Chrome has sporadic support for screen readers.) It does not work with JAWS on Internet Explorer but IE seems to have two problems. The first is that your font-size:initial does not work on the :before. I had to set it to font-size:16px. Second is that IE does not correctly compute the text to be read as noted in step 2.F.ii above. IE is not honoring the content property so "unwanted garbage" is still read (and "lovely replacement" is not read). Since step 2.F.ii is a W3 spec, I'd say IE has a bug.
If content were correctly read by IE, then there might still be a problem. Since font-size:inherit doesn't work in IE, visibility:inherit might not work either. (I tried a simple case and it didn't work. Setting visibility:visible on :before also didn't work on IE.)
Problem: I have a div that is nested inside a span tag with the role of button, whenever the span button is focused, what I want to have happen is the screen reader 'read' the text in the nested div --> p tag when the span receives focus
<span role="button" tabindex = 0>
<div id= "nestedDiv" aria-hidden ="false" tabindex = 0>
<p tabindex =0> Read this text </p>
</div>
</span>
I tried different screenreaders and different browsers, same issue, it doesn't read the div, it just skips over to the next readable element.
I tried this in NVDA + firefox and it reads "read this text. button" when I tab to the span. Which browser are you having trouble in?
You could try adding an ID to the paragraph such as <p id="foo"> and add aria-labelledby="foo" to the <span>.
However:
Karl Brown's comment is 100% accurate - it's best to use semantic markup. Does the span do something? If so, it should be a button. Does it bring you to a different page? If so, it should be an anchor.
Also, why so much tabindex? It takes three tabs to get outside of this element, which is not good. If you use proper semantics you wont need tabindex and you wont need any aria attributes.
I noticed on a few places (mainly Youtube's comments), there are "textbox" instead of the normal "textarea".
<div role="textbox" aria-multiline="true"></div> vs <textarea></textarea>
Also I see <div role="textbox"></div> instead of <input type="text">
Is there any functionality advantages to use role="textbox" instead of textarea or input? Or is this just pure preference? For example, is it easier to modify or edit using Javascript?
As you see above, I am selecting the comment box with Chrome's inspector.
Now I added text to the comment box, and the text appears inside the div element stated above when viewing Chrome's inspector.
I'm not sure where you are seeing that a div should be a textbox, but that's incorrect. The tag is input, not div.
But, to your larger question the role attribute pertains to the WAI-ARIA standard, which relates to user accessibility for those who use assistive technologies, such as screen readers. It allows those users to navigate a page more easily because the screen reader has a better idea of what elements are what on the page.
There are no new functions that the text field takes on because of the use of this attribute. ARIA is about accessibility.
You can read a bit more about this, particularly relating to text fields at: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_textbox_role
In an earlier version of the http://getbootstrap.com/components/#pagination page/section, it had the code:
<nav>
<ul class="pager">
<li class="previous"><span role="presentation">←</span> Older</li>
...
</ul>
</nav>
This has been changed to:
<nav>
<ul class="pager">
<li class="previous"><span aria-hidden="true">←</span> Older</li>
...
</ul>
</nav>
The left arrow (←) is purely decorative, and doesn't need to be announced by a screen reader. According to http://www.w3.org/TR/wai-aria/roles#presentation:
presentation (role)
Example use cases:
An element whose content is completely presentational (like a spacer image, decorative graphic, or clearing element);
An image that is in a container with the img role and where the full text alternative is available and is marked up with aria-labelledby and (if needed) aria-describedby;
...
Whereas:
aria-hidden (state)
Indicates that the element and all of its descendants are not visible
or perceivable to any user as implemented by the author.
I understand that 'role=presentation' is really talking about the semantic meaning of the element, but it seems like the left arrow is directly analogous to 'a spacer image, decorative graphic, or clearing element', and is certainly 'visible or perceivable to any user'.
What's the correct design pattern here? Is the meaning of 'aria-hidden' changing to allow for this specific limitation of 'role=presentation'?
The role attribute is used to override the default mapping of the role of the HTML element to the accessibility tree. This has no effect on the text content of the element.
For example, role="button" on a div will allow the div to be announced as a button but will not change the fact that the text of the div (e.g. "Submit") will still be announced as the accessible name.
In ARIA 1.1 the presentation role has been given a synonym of "none" to better represent its semantic http://www.w3.org/TR/wai-aria-1.1/#none
The attribute aria-hidden is used to hide the element itself and the content (accessible name) of the element from the accessibility tree while keeping it visible in the document. This semantic has always been the case. It has not changed.
unobf is correct but sometimes it helps if you think of what the screen reader user will experience. Consider this simple example:
<div role='button' tabindex=0>alpha</div>
<br>
<div role='presentation' tabindex=0>beta</div>
<br>
<div role='button' tabindex=0>gamma</div>
<br>
<div role='button' tabindex=0 aria-hidden='true'>delta</div>
<br>
<div role='button' tabindex=0>epsilon</div>
If you're using VoiceOver or the virtual PC cursor in JAWS, both will allow you to put your focus on the role='presentation' item and will not state a role but it will say 'beta'. (I like the new role='none' that unobf points out in the 1.1 spec. It makes it clearer that the screen reader should not state any role when it's set to 'none'. As the spec says, it was a little confusing using 'presentation'.) So the presentation item isn't really hidden to the screen reader. You're just telling the screen reader that it doesn't have a role.
Aria-hidden, on the other hand, completely removes it from the screen reader, except in my poor example (which is intentional). If you're using VoiceOver or the virtual PC cursor in JAWS, both will skip the aria-hidden button. The screen reader user won't know it's there. But if the JAWS user is TABBING through the page, they will land on the aria-hidden button because it's a tab stop. But since it's aria-hidden, JAWS gets a little confused on what to say. When I tried it (FF 38 and JAWS 16), it said 'beta', which is the text from a previous <div>. In general, you don't want to aria hide something but make it keyboard accessible. That's just a weird scenario.
Going back to bootstrap's old example, since they used role='presentation' and it's a <span> tag, the VoiceOver and virtual PC cursor JAWS user will both be able to put their focus on the <span> element, which is probably not what they intended. Since the arrow is just for decoration, it makes sense to aria hide it.