Is it ok to combine aria-label and aria-describedby? - html

I have searched around and I'm not finding any information if it is ok to combine the aria-label and aria-describedby for an element and if it would cause confusion to someone using a screen reader?
I have a list of many items and each item has a title and then next to the title is a PDF icon to download a pdf of the item, like this:
<ul>
<li>
<div id="item-{{item.id}}">{{item.title}}</div>
<button class="icon-pdf"></button>
</li>
</ul>
I am wondering if I can do something like this and if it would still make sense to the user and if screen readers would handle this scenario:
<ul>
<li>
<div id="item-{{item.id}}">{{item.title}}</div>
<button class="icon-pdf"
aria-label="Download PDF button"
aria-describedby="item-{{item.id}}">
</button>
</li>
</ul>
Perhaps it would be better to convert the button to a link and just use a title attribute like this?
<a href="javascript:void(0);//Download PDF"
class="icon-pdf"
title="Download PDF"
aria-describedby="item-{{item.id}}">
</a>

Short Answer
There is no need to add the extra information you are trying to add if you use a hyperlink and recommended practices of adding file type and size in brackets (oh and language if your site is multi-language).
Long Answer
To answer the original question, yes you can use aria-label and aria-describedby together. They serve different purposes.
aria-label is for providing a usable name for a control, it overrides any semantically derived information (i.e. button text).
aria-describedby is used to provide additional information for custom controls etc. It can also be used to provide hints to screen reader users. Also this answer I gave has information about support for aria-describedby etc. Something to consider.
If you use them together you would get the aria-label read first and then get the aria-describedby information read after.
Quick example of aria-label and aria-describedby together
<button aria-label="read first" aria-describedby="extra-info">Not Read Out</button>
<div class="visually-hidden" id="extra-info">This would be read second</div>
In the above example it would read "read first, This would be read second", notice the "Not Read Out" original button text is completely overwritten.
Your use case doesn't really need these though
With all of the above being said, here are a few suggestions for your use case as there is no real need for WAI-ARIA here:-
Even if a document is being downloaded on the same page you should use a hyperlink. The main reason for this is when JavaScript fails on your page (or for those who still browse the internet without JavaScript) there is a fallback so the document is accessible. Additionally this helps with SEO if you want the document to get indexed etc. (I know, I dare to mention SEO on Stack Overflow!). Finally it is semantically correct, it is a linked file and that is ultimately what hyperlinks are for.
If information is useful to screen reader users it is probably also useful to other people, i.e. those with cognitive impairments. However in this use case it would be better that the control that performs the action contains all the relevant information.
Generally (if your design can be adjusted to allow for it) it is a good idea to include the file type and file size as additional information in brackets next to any download.
Don't use the title attribute, it is not a very accessible attribute and is useless to most screen reader users as it will not be announced. (It is also useless to any keyboard only users etc.)
WAI-ARIA is useful for supplemental information, the general rule is a control should work without it and WAI-ARIA is for progressive enhancement.
Putting it all together
You will notice in the following example I have completely removed the need for the "Download PDF" extra information.
Because a hyperlink is semantically correct and the fact we state it is a PDF in brackets (plus file size) there is no need to tell people that this will download the PDF, they already know this!
I have done two different examples for you, one with the file type and size visible, one with them visible only to screen reader users.
I have added comments to the first example to explain bits. Any questions just ask!
body {
font-family: Century Gothic;
background: #272727;
}
.btn {
float: left;
width: 25%;
height: 30px;
padding: 1px 0px;
min-width: 200px;
margin: 2% .8%;
overflow: hidden;
background: #527EBF;
}
.btn:hover {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
border-radius: 5px;
background: #666;
}
.btn a {
text-decoration: none;
}
.btn img {
width: 22px;
margin: 0 5px;
transition: all .5s ease;
position: relative;
left: 0;
transform: scale(0.7);
}
.btn .container span.text {
font-size: 12px;
color: #fff;
position: relative;
left: -3px;
top: -8px;
transition: all .45s ease-in-out;
}
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
<div class="btn">
<a href="link-to-pdf.pdf"> <!--obviously if you want to intercept this with an event listener in JS then do so but leave the URL for fallback-->
<div class="container">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/PDF_file_icon.svg/267px-PDF_file_icon.svg.png" aria-hidden="true"/> <!-- hide the icon from screen readers with `aria-hidden`, preferably use a **inline** SVG instead of external image to save an uneeded request. -->
<span class="text">Item Name (PDF, 21MB)</span> <!-- added the file type and size as this is useful information for people, made it visible to all. If yourdesign won't allow for this then hide it as per second example -->
</div>
</a>
</div>
<div class="btn">
<a href="link-to-pdf.pdf">
<div class="container">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/PDF_file_icon.svg/267px-PDF_file_icon.svg.png" aria-hidden="true"/>
<span class="text">Item Name Hidden file size info <span class="visually-hidden">(PDF, 21MB)</span></span>
</div>
</a>
</div>

Related

Read more Links do not have descriptive text

I have a page which contains a list of items. Each item contains a 'Read more' link that points to a different page. But when I run the lighthouse tool on that page, it complains that links do not have a descriptive text. Now I cannot change the Read more text here.
Read more
Read more
Read more
Is there any other way to resolve this?
I had the same problem.
Attribute aria-label does not works, lighthouse still display issue.
I fixed it by adding hidden detailed text inside link.
Read more<span class="screen-reader-text">Details</span>
<style>
.screen-reader-text {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
-webkit-clip-path: inset(50%);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute !important;
width: 1px;
word-wrap: normal !important;
word-break: normal;
}
</style>
Note about .screen-reader-text: this CSS grabbed from wordpress default Twenty Seventeen theme.
Yes, you can use aria-label in order to provide more descriptive text to Assistive Tech such as a screen reader.
Read more
Assistive tech will read the contents of the aria-label out instead of "Read More".
Bear in mind that the text you enter should be enough to know where the link will take you and not context dependent (the link text should make sense on its own) if possible.

What is better practice use <a> or <a role="button"> for accessibility?

I have a download link, and I can't find any good accessible solutions for how I should handle this situation.
I have a common rule of thumb I'm following: "Buttons Do Things, Links Go Places"
My scenario is that I have a button which triggers a document download (same page)
I believe that this should be an anchor with a role of a button because its explicitly not triggering a redirect or navigation:
<a role="button" href="download.docx" download>Download File</a>
However, its strongly recommended to not change the native semantics of an element.
My colleague suggests this would be the solution
<a href="download.docx" download>Download File</a>
However: the issue with this is that the Screen reader doesn't (in my opinion) give a clean enough output. It mentions this element is a link, which could be confused with a redirect.
The role="button" solution tells the screen reader to inform the user that this link is acting like a button which I think is more specific for our particular case of the "download button".
Any clarity would be greatly appreciated.
I'm referencing: https://css-tricks.com/building-good-download-button/
Short Answer
A hyperlink is correct and expected behaviour. As your link text contains the word "download" there will be no confusion, you do not need to do anything else.
However there are additional pieces of information for downloads that you should include if you are able such as document type and file size.
Oh and please do not use the title attribute.
Relying on the title attribute is currently discouraged as many user agents do not expose the attribute in an accessible manner as required by this specification (e.g., requiring a pointing device such as a mouse to cause a tooltip to appear, which excludes keyboard-only users and touch-only users, such as anyone with a modern phone or tablet).
Source: HTML standard
Long Answer
Firstly, please do not add the title attribute to your download link, it is useless for screen readers on mobile, it is useless full stop on mobile for everyone else, keyboard users do not see it etc. etc.
Instead you should (with all links not just this particular link) provide extra information.
The additional file information that should be provided is:
File Type ("Word Document" or "docx")
File Size (in KB)
Optional - How the link behaves (new window if applicable).
In the examples below I have assumed new window just for an example, as you are downloading a document you do not need to add this information as it is assumed all actions are performed in the same window and you only need to add this if you open a new window.
Quick aside: "Buttons Do Things, Links Go Places"
A hyperlink is correct semantically so don't worry about that.
A slight variation to your phrase (which I like and am stealing by the way!) should be "Buttons Do Things, Links point to URLs". Not quite as "pithy" but better for helping you make decisions. If you can type it into the URL bar then it is a hyperlink, guaranteed.
Now onto your options...
Full information in the "button"
Now if your design and site allows it is recommended to provide the additional file information to everybody not just screen reader users.
The following fiddle shows one way you could do this
a{
display: block;
height: 50px;
width: 450px;
font-size: 22px;
padding: 10px;
background-color: #333;
border: 2px solid #666;
border-radius: 4px;
color: #fff;
text-decoration: none;
font-weight: bold;
text-align: center;
}
a span{
font-size: 16px;
font-weight: normal;
color: #ccc;
}
<a href="document.docx" download>Download Document<br/><span>Microsoft Word (docx), 246KB (Opens in New Window)</span></a>
A more realistic way to do this
Now in the real world the odds of you being able (or allowed) to show all that information in the button is very slim, but it is still useful to screen reader users even if you can't provide it to everybody.
At this point your best option is "visually hidden text".
Yup, aria-label, aria-labelledby etc still don't have full support sadly and our aim is maximum usability.
So good old visually hidden text works all the way back to IE6, if your site works that far back it would be a miracle anyway (I know mine don't!)
The below example uses my visually hidden text class, as support is better than sr-only and other screen reader only classes and it is futureproofed for the next few years (as clip has been deprecated).
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
a{
display: block;
height: 28px;
width: 450px;
font-size: 22px;
padding: 10px;
background-color: #333;
border: 2px solid #666;
border-radius: 4px;
color: #fff;
text-decoration: none;
font-weight: bold;
text-align: center;
}
Microsoft Word (docx), 246KB (Opens in New Window)</span>
aria-describedby - A hybrid approach
If you can't use the first option then we could fall back to a hybrid approach.
We make the button nice and prominent, but underneath add the file size info etc.
For this we use aria-describedby which points to the ID of the paragraph below.
THe only down side is a few browser / screen reader combinations may not support it but hey, life is about compromise and the below is clean and you are more likely to be able to implement it than all the information in the button itself.
a{
display: block;
height: 28px;
width: 450px;
font-size: 22px;
padding: 10px;
background-color: #333;
border: 2px solid #666;
border-radius: 4px;
color: #fff;
text-decoration: none;
font-weight: bold;
text-align: center;
}
p{
margin-top: 10px;
font-size: 16px;
font-weight: normal;
color: #444;
}
Download Document
<p id="doc-info">Microsoft Word (docx), 246KB (Opens in New Window)</p>
What should my link text be?
Your current link text may just be an example, but it should be descriptive.
If the document is about cheese strengths it should be "Download Cheese Strength Report".
If the title is complex then yet again use visually hidden text to give a more descriptive name to your link. This is because screen reader users do not always navigate in a linear fashion. They may decide to loop through all the links on a page, or headings, or sections etc.
For this reason if you had 3 documents on a page and their text was "Download Document" this would be completely useless to a screen reader user.
All links on a page should make sense without any surrounding information to support them.
UPDATE
It seems that the title may hurt/confuse the screen readers, so according to W3C the best way to improve a11y is by making the anchor text relevant and descriptive
More info about this, you can find here also
Old solution (do not use)
You can always use title attribute (with a copy different than the text), something like:
Download File
Here's a comparison
See more info here

Is there a way to fix Accessibility Issues on my website relating to third party tags?

After running google's lighthouse extension on a web page, I got a flagged error for button not having discernible text, realting to the html tag below:
<div class="invitation-chat__close" role="button" data-dl-element="button" data-dl-name="No, don't start">
My report suggests this:
To solve this violation, you need to:
Fix at least one (1) of these issues:
Element does not have inner text that is visible to screen readers
aria-label attribute does not exist or is empty
aria-labelled by attribute does not exist, references elements that do not exist or references elements that are empty
aria-labelled by attribute does not exist, references elements that do not exist or references elements that are empty
Element's default semantics were not overridden with role="presentation"
Element's default semantics were not overridden with role="none"
Element has no title attribute or the title attribute is empty
Is there any way of implementing any of these suggestions, without interrupting the functionality of my third party program (which is just a chatbot).
Yes there are several ways you can do this.
The reason you are shown this error is for screen readers, they need some programatically determinable text in order to tell the user what the button does.
You only showed part of the button HTML but my guess is you are only using an icon within it so there is no way for the screen reader to work out useful information for the end user.
Two ways you could fix this are:-
1. Add an aria-label
WAI-ARIA is used to provide extra information to screen readers. If you change your markup to include an aria-label as follows this lets screen reader users know what the button does:-
<div class="invitation-chat__close" role="button" data-dl-element="button" data-dl-name="No, don't start" aria-label="open chat or whatever is the action of the button">
The aria-label tells screen readers "ignore the contents of this element when determining how to announce this item, instead use this text I have defined".
2. Add some visually hidden text.
Unfortunately aria-label does not have universal support.
As such the better way to do this is with "visually hidden text" (text that is not visible but accessible to screen readers).
Please see this answer I gave about sr-only text to understand that further and for the reason to use the below class.
For your example all you need to do is add a span with the visually-hidden class containing text that is descriptive of the button purpose.
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
<div class="invitation-chat__close" role="button" data-dl-element="button" data-dl-name="No, don't start">
<span class="visually-hidden">Open chat or whatever is appropriate text for the button</span>
<!-- other HTML such as icon -->
ICON
</div>
Further suggestions.
As I would imagine you are using HTML5 I would encourage you to change your markup.
Instead of a <div> with a role="button", just use a <button> element.
Not only is this more robust it is also easier to maintain and it has all of the functionality baked in such as focus indicators, click events etc.
This yet again is down to support, although support is much better for role than other WAI-ARIA attributes.
<button class="invitation-chat__close" data-dl-element="button" data-dl-name="No, don't start">
<span class="visually-hidden">Open chat or whatever is appropriate text for the button</span>
<!-- other HTML such as icon -->
ICON
</button>
What if you cannot change the source code?
At that point you need to do the same but with JavaScript.
Once your component has initialised target the offending div using a query selector and insert the relevant HTML.
const myNewHTML = '<span class="visually-hidden">Open chat or whatever is appropriate text for the button</span>';
let el = document.querySelector('[data-dl-name="No, don\'t start"]');
el.innerHTML = el.innerHTML + myNewHTML
console.log("NEW INNER HTML", el.innerHTML);
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
<div class="invitation-chat__close" role="button" data-dl-element="button" data-dl-name="No, don't start">
<!-- other HTML such as icon -->
ICON
</div>
Fix all of the following: Element is in tab order and does not have accessible text Fix any of the following: Element does not have text that is visible to screen readers aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute More videos

How to make an HTML link displayed as an icon accessible?

I have some links that are displayed only as icons (don't have any text):
.icon-link {
background-image: url(...);
}
How do I make this link accessible for people not accessing the website visually (using screen readers)?
I see few approaches possible, but cannot find any resources on which one is actually right, or best supported:
Adding aria-label attribute on <a>
Adding title attribute on <a>
Adding text inside <a> and then hiding it visually with CSS
Short Answer
Use visually hidden text.
Longer answer
Adding a title offers very little in the way of accessibility. Here is an interesting article on the subject, it links out to further information.
So with that in mind that leaves option 1 and 3 as viable options, however the best compatibility is using visually hidden text.
You see support for aria-label is surprisingly low (scroll down the page to the aria-label section), whereas visually hidden text using the example below will cover browsers all the way back to IE6!
I answered about the most robust way to do visually hidden text (with explanations of why I do each item) in this stack overflow answer. I have copied the same below just for your reference.
For your use case just add a span within the link with the visually-hidden class.
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
<p>visible text <span class="visually-hidden">hidden text</span></p>
Added Bonus of visually hidden text
As #QuentinC pointed out in the comments there is another great reason to use visually hidden text over the other methods.
If a user uses a browser that does not support CSS (there are still a few text only browsers that people use) then the text will be displayed.
Always reconsider using visually hidden text. Not because it is bad, but because it leads to false belief that the solution is accessible for everyone when it's only accessible to a small subset of the population.
Using hidden text won't help people not using screenreaders to know the action performed by the link when meaning of the image might be difficult. Screenreader users are a small part of the population targetted by accessibility rules.
Regarding the title attribute, it won't hurt anyone to improve accessibility if you inform standard mouse users of the action performed by the link. It will help them. If a title attribute is not always recommended, you might opt for any solution that would show the text when the element is focused with the mouse or with the keyboard.
You also must remember that not showing text will not help people using voice navigation or eye tracking device.
When using the title attribute, you must always consider using it conjointly with the aria-label attribute, and not replacing one with the other.
EDIT: simple example
.icon-link {
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='50px' width='120px'><text x='0' y='20' font-size='20'>🍕</text></svg>");
content: '';
background-repeat: no-repeat;
width: 20px;
height: 30px;
display: inline-block;
}
#pizza {
position: absolute;
display:none;
background:white;
color: black;
margin-left: 20px;
}
a:focus #pizza, a:hover #pizza {
display: block;
}
<div id="pizza">Pizza!</div>

How to hide a text and make it accessible by screen reader?

I have a simple text that gets updated on an action and I want that to be announced by the screen reader. But I don't want that text to be visible on the web page. I tried display: none and visibility: hidden, but seems like they are not accessible by the screen reader softwares. I found a way to make this work - that is by absolute positioning the element all the way with negative 999999 value which will make it off screen and hidden from the webpage. I am not really a fan of this solution. Is there a more elegant way to achieve this?
<span class="aria-invisible" aria-live="polite">5 selections have been made.</span>
.aria-invisible {
display: none; //either of these two attributes
visibility: hidden;
}
A better solution to the bootstrap "sr-only" class.
There are numerous problems with the Bootstrap "sr-only" class.
First of all you will see from this discussion that a negative margin can cause issues on VoiceOver.
Secondly you must account for words wrapping one per line as screen readers do not read line breaks
Finally clip has been deprecated.
To fix point 1 simply don't add a negative margin.
To fix point 2 add white-space: no-wrap to ensure words do not end up 'one per line' and cause words to get smushed together.
To fix point 3 we add clip-path: inset(50%) as this clips to a 0px square, we keep clip as at the moment this has great coverage, clip-path is used to future-proof your solution.
Please find below a much more robust class, as of yet I have not found a screen reader / browser combo that does not work as expected with this.
I have this class on a few different forums being tested, so far so good but if someone can find a problem with it please let me know as I will be submitting it everywhere.
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
<p>visible text <span class="visually-hidden">hidden text</span></p>
I did encounter this problem in the past.
Bootstrap has this sweet class sr-only that actually hides the content on the webpage but is accessible by the screen readers. You can check this link
Moreover, if you are not using bootstrap, you can simply implement the class yourself in your code.
.aria-invisible {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
<span class="aria-invisible">5 selections have been made. </span>
I hope this helps.
Using aria-label attributes is the way to do (example below)
Is there a more elegant way to achieve this?
Do not hide the element. Yes. I am not answering your question, but I am addressing the problem.
Screenreaders are only a subpart of assistive technologies used by a small part of people targeted by accessibility guidelines.
Imagine using a screen magnifier for instance where you do not have a global view on the full screen. Imagine having some cognitive disabilities which makes difficult for you to count or remember elements.
If you do consider that an information is important for blind people, then it's surely is for them AND for other people.
Now, instead of it being a long text, it can be a small counter with appropriate aria labelling:
<div role="status" aria-live="polite" aria-label="5 selections have been made.">
5 selections
</div>
I had the same problem with the text being out of position with the visually hidden class mentioned above. Some small changes to the class fixed this issue for me
.visually-hidden {
border: 0;
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: auto;
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
white-space: nowrap;
}