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

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>

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.

How to fix "name property of a focusable element must not be null"

Im using UI accessibility insights to test my react app on windows.
I get a lot of "name property of a focusable element must not be null" and a lot of "focusable sibling elements must not have the same name and localizedcontroltype" errors.
I have no clue how to fix these errors, and i can't find anything decent in google.
To solve the first one i tries adding the name ot id or aria-label attr to the buttons, but nothing changed. Any idea on how to get around this?
example of button that's failing the test:
<button
className={css.button}
onClick={() => setIsTipOpen(!isTipOpen)}
>
<Icon type='Girl'/>
</button>
Screen readers need to be able to announce something to their users. The problem with an icon in a button is there is no way to programatically determine the button text.
One way to fix this is to add an aria-label to the button element.
Another way to do this is visually hidden text. This is text that is not visible but still accessible for screen readers.
In the below example you will see there is no visible text (as it should be an icon inside) but a screen reader user would hear "button, A girl", just make sure the button text makes sense as an action (so I assume this button would be "gender female" or something).
Visually hidden text is preferable as for people who use text only browsers the text within the button is still displayed (as CSS is ignored in a text only browser) and support is 100% all the way back to IE6 (whereas aria-label support is not 100%).
.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 */
}
.your-button-classes{
width: 100%;
height: 50px;
background-color: #333;
}
<button
class="your-button-classes"
onClick="someAction"
>
<Icon type='Girl'/>
<span class="visually-hidden">A girl</span>
</button>

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

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>

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;
}

What's the correct way to hide the <h1> tag and not be banned from Google?

The website I am working on uses an image defined in CSS as the main logo. The html code looks like this:
<h1>Something.com | The best something ever</h1>
I would like to display just the image defined in CSS and pass the information from the h1 tag to the search enginges only.
What's the correct way to do this? Google is very strict about this, I know that display:none is wrong, what about visibility: hidden ?
Thanks in advance!
You should be fine with visibility: hidden.
That said, if your image is part of the content (and I would dare to say that a company logo is content, not presentation), and you care about accessible html, you should consider changing your code to include the image as a img element with title and alternate text, instead of a css background-image.
Additionally, if you hope to attract search engines to the keywords inside the <h1> element, you might want to include those words more than once in the page. The page title is a much more relevant place than the h1 element, for example.
The easiest, foolproof, best for SEO solution would be
<h1><img src=logo.png alt="Something.com | The best something ever"></h1>
set the image as the background of your h1 (set the width/height so it fits) then set your text-indent to something crazy like -9999px. That way when css is disabled (such as being crawled) the bot will see the text in the header instead of the background.
example:
CSS
#myHeader {
width:200px;
height:50px;
background: url('lcoation/of/the/image.jpg') top left no-repeat;
text-indent:-9999px;
}
HTML
<body>
...
<h1 id='myHeader'>HELLO WORLD</h1>
...
</body>
The "correct" way to do this is to have the text in the title bar or in your page's meta text.
<h1 style="font-size: 2px; margin: 0px;">Something goes here</h1>
Works like a charm.... ;-) The screen readers will interpret it and won't affect your SEO.
You're not going to get good SEO results if you, first hide the <h1>, and second use generic phrases inside the <h1>.
Don't just use the <h1> for sizing, you can use classes to style.
<h1> tags should contain keyword rich information such as:
Automotive Repair
Automotive repair being the keyword that relates to the particular page I'm theoretically working on.
Hope that makes sense.
I think that visibility: hidden; would work fine. Have you tried it yet?
Does your web site consist of just one single page?
Otherwise you should put the headline of each page in the h1 tag, not the tagline of the site. Repeating the same headline on every page would make it pretty much useless.
Resizing the block would work:
h1 {
overflow: hidden;
width: 1px;
height: 1px;
}
A full article in this matter is explained here https://www.paciellogroup.com/blog/2012/05/html5-accessibility-chops-hidden-and-aria-hidden/
So , when i work i use this code to support screen reader as well as hide some h1's and use pictures instead of it like (logo)
.offscreen{
position: absolute;
clip: rect(1px 1px 1px 1px); /* for Internet Explorer */
clip: rect(1px, 1px, 1px, 1px);
padding: 0;
border: 0;
height: 1px;
width: 1px;
overflow: hidden;
}
to find more follow the link