Tips on Making Sure Hidden Content is Accessible (or Not!)

Tips on Making Sure Hidden Content is Accessible (or Not!)

As we've previously discussed, screen reader users are able to navigate by specific pieces of content such as headings, landmarks, links, and more. In doing so, folks who rely on this technology are able to find a piece of content quite quickly.

An issue may arise, however, when links, labels, buttons, etc, are not sufficient in conveying their purpose; their purpose in being should be explained well enough within their accessible name. If the name is not clear or perhaps the same type of element is repeated with the exact same name, this may lead to confusion or frustration for the user.

Another issue may appear when sighted keyboard-only users are navigating through content only have the focus indicator disappear! This is often due to content that is, "off-screen" yet is reachable via keyboard. Again, this can also lead to some confusion.

Let's review some examples and how to alleviate these potential issues.

Repeated content

Repeated content can be thought of as content which appears multiple times throughout a single page or view. This content typically exists as callout links or imagery that exists within list or table cells.

As previously discussed, the issue here is when a screen reader user navigates solely by a specific type of content: links, form controls, headings, etc. When the user hears the repeated content with no further context, this is when we might run into some usability issues.

Take, for instance, the classic "Read more" link. These links often appear on blog or news listing pages, encouraging the user to click to reveal more details.

An example link might be marked up as:

<a href="article/how-to-make-pasta-sauce.html">
  Read more
</a>

On a blog post page with links to posts, if someone were to navigate by links alone, they'd hear something along the lines of,

"Read more, link – Read more, link – Read more, link"

With each link sounding the exact same as a result of sharing the same text label, there's no way to determine where any one particular link may lead to.

Providing context without disrupting the design

There are a couple methods available in order to help provide more context for links such as these without disrupting the intended design.

Of course, adding extra visible text would be ideal as this would benefit people with cognitive impairments with clear labeling or those with low-vision who rely on zoom software. But, if you're unable to sway things in this direction, let's look at a couple of alternatives.

Visually hidden text

Using the CSS .visuallyhidden class definition is a way to visually hide text content from sighted users, yet, have the content remain available for screen reader users. This is also sometimes called sr-only, accessibility, or other related class names.

<a href="article/how-to-make-pasta-sauce.html">
  Read more
  <span class="visuallyhidden">about How to Make Pasta Sauce</span>
</a>

Coming back to the "Read more" link example, we see here the HTML looks the same as before but with the addition of a new span element. This span features the .visuallyhidden class resulting in the text content within will be hidden from sighted users, preserving the original design, but also provides the extra context needed for screen reader users.

Now, when someone using a screen reader encounters this link, they would hear,

"Read more about How to Make Pasta Sauce, link"

The aria-label approach

Using the aria-label attribute is an alternative to the .visuallyhidden CSS method. This approach directly sets the intended hidden content as the accessible name for the element.

Revisiting the link example from before, this code is a little bit cleaner and easier to read compared to the .visuallyhidden example.

<a
  href="article/how-to-make-pasta-sauce.html"
  aria-label="Read more about How to Make Pasta Sauce"
>
  Read more
</a>

One thing you may have noticed is the repeat content of, "Read more" within the aria-label attribute. This is required in order for a screen reader to announce the text in its entirety as a result of using the aria-label attribute, the attribute value takes precedence over anything else that's placed within the link element. In other words, when you apply the aria-label attribute, any text within the element will be completely ignored by screen readers.

WCAG success criteria

This comes back to 2.4.4 Link Purpose which states:

"The purpose of each link can be determined from the link text alone or from the link text together with its programmatically determined link context, except where the purpose of the link would be ambiguous to users in general."

A few more examples…

Let's review a couple more common situations where off-screen text would be helpful.

A table of buttons

Imagine a table of content items, and each item can be removed from the table using a button control. These controls might be marked up as:

<button>Remove</button>

Since we know that screen reader users are able to navigate by specific content, hearing "Remove" multiple times (assuming there's multiple items in the table) is not very helpful. Remove what, exactly?

Let's use an aria-label attribute to help give context to each of the controls:

<button aria-label="Remove {item title}">
  Remove
</button>

With the aria-label added each instance of the button control and the {item title} added to its output, we can provide extra context for each control.

Star ratings

It's common to see a visual representation of a rating on a product page. Often this is represented by a set of icons, typically star icons, representing a 0 to 5 range. The visual meaning of the star image is typically understandable enough for sighted users, but how do we provide an accurate text alternative for someone using a screen reader?

Here's a typical example of a star rating markup outputting icons, using an i element to output a set of icons:

<i class="icon icon-star star-4"></i>

Guessing by the class name, star-4, this might output a "4 out of 5" visual rating, but if someone's using a screen reader, there's nothing available to convey the same information.

In order to do so, we can add some .visuallyhidden text to provide a text alternative (and also swap the i element for a span as i features semantic meaning):

<span class="icon icon-star star-4">
  <span class="visuallyhidden">4 out of 5 stars</span>
</span>

Now when a screen reader encounters this content, the .visuallyhidden text alternative will be announced, providing content for the user to understand the current product rating:

"4 out of 5 stars"

Offscreen navigation

A common pattern for web design these days is to hide primary navigation in an "offscreen drawer", toggled by a hamburger menu control. This pattern is usually set in place for a small screen or mobile context, though it's also been seen on desktop sites as well.

An accessibility issue with this pattern arises when the drawer content container is positioned off-screen via CSS position property only. The menu is tucked away visually, however, when someone using a keyboard navigates through page content, these visually "hidden" links will still be focusable, essentially creating hidden tab-stops. This is an issue as the keyboard-only user is not able to determine the current focus position on the screen and may become confused or frustrated.

Completely hiding content

In order to hide content completely from sighted users, keyboard-only users, and screen reader users, there are a few methods we can take:

  • Applying CSS display: none to the drawer container will accomplish the desired effect of hiding the content from keyboard users. One note on this solution is the display property cannot be animated without some extra JavaScript setting the property value at a specific time.
  • Applying the CSS visibility: hidden property essentially produces a similar result as using display: none. The difference here is the visibility property is easier to animate, especially when used alongside the opacity CSS property.
  • Lastly, applying the HTML hidden attribute to the drawer container would produce the same result as the CSS display: none property; hiding the content completely from visual and non-visual users alike.

If visually hidden, hide from keyboard and assistive technology users, too

The purpose of this is to ensure an equal user experience. If something is visually hidden from view, this content should also be hidden from keyboard and screen reader access.

WCAG success criteria

This comes back to 2.4.3: Focus Order which states:

"If a Web page can be navigated sequentially and the navigation sequences affect meaning or operation, focusable components receive focus in an order that preserves meaning and operability."

When we use or see the pattern target="_blank" rel="noopener" in a link, it's our responsibility as web authors to include a notice that the link opens a new window.

Why? Without this context, people might believe they're following an internal site link in the same browser window. Opening a new tab on behalf of the user would cause extra work for sighted keyboard-only users and screen reader users. If they're unprepared to move away from the current site, they'd need to put in the effort to switch back to the previous tab or window.

Give power to the user—let them decide how they'd like to proceed

The idea is to give power to the user; inform the user of what might happen in order to allow a decision to be made on how and when they'd like to proceed.

How to accomplish this

One recommended solution to informing people that a link opens a new window involves:

  • Adding a new container element to the DOM which houses required variants of the warning message
  • Each variant element will have a unique IDREF to reference elsewhere in the app
  • When a link features the target="_blank" rel="noopener" attributes, add the aria-describedby attribute, setting its value to the appropriate id of the message to be announced

Let's review an actual example to get a better understanding for what's involved.

Example pattern

First, add the HTML container (aka screen reader sprite sheet) which will hold the variations of the warning message:

<div hidden>
  <span id="new-window-0">Opens in a new window</span>
  <span id="new-window-1">Opens an external site</span>
  <span id="new-window-2">Opens an external site in a new window</span>
</div>

You may notice this div container features the hidden attribute. This is to ensure this chunk of text is not visible nor are screen readers able to find and read the text out of context.

Now that we have these warning messages available, we can easily reference them as required.

Next up, including the warning message in a link.

<a
  href="https://mysite.com"
  target="_blank"
  rel="noopener"
  aria-describedby="new-window-0"
>
  My site
</a>

With the aria-describedby attribute pointing toward the first warning message element, the link reads:

"My site — Opens in a new window"

(Note: The long-dash here is just to point out that aria-describedby generates a pause in-between the link text and the warning message content.)

With this in place, the link text will be read aloud, pause, then the warning message that the link opens a new window.

What about a visual affordance?

I did mention sighted keyboard-only users earlier. How do we inform a sighted user that a new window will open, visually?

One approach is to use an icon alongside the link text. With an icon, a sighted user will get the notice that something different might occur when I activate this link.

I don't think an icon is required in all contexts, such as a listing of social media icon links, or perhaps copyright style links in a footer section. When it comes to links in body copy, however, it's a good idea to add some sort of visual indicator, just as folks using a screen reader get an audible notice.

An example of the visual indicator

Let's say you've got an icon that's suitable. Usually a boxy looking icon with an arrow pointing in an upward direction, similar to the Shopify Polaris External Link icon.

Now that we have our icon, let's include it in the link:

<a
  href="https://mysite.com"
  target="_blank"
  rel="noopener"
  aria-describedby="new-window-0"
>
  My site
  <svg role="presentation" aria-hidden="true" focusable="false" ...>
    <path>
      <!-- ... -->
    </path>
  </svg>
</a>

With the aria-describedby attribute on the link along with the "new window" icon alongside the text, all users will be able to make an informed decision if and when to activate the link, either now or later when they're ready.

WCAG success criteria

This comes back to 3.2.2 On Input which states:

"Changing the setting of any user interface component does not automatically cause a change of context unless the user has been advised of the behavior before using the component."

Resources:

Back to blog