Heading order and page landmarks
Heading order motivation
Someone who is using a screen reader may jump around the headings on a page to quickly scan content. Headings have a hierarchy: A page should have only one h1 corresponding to its title, and h2s are used for major subsections, h3s are for subsections of h2s and so on.
If headings are used our of order, such as an h2 being placed below an h3 despite the h2 content being a subsection of h3, then the user may be confused. Skipping heading levels entirely, such as going from an h2 to an h4, can also cause issues.
It may be tempting to use headings out of order based on their styles, but this should not be done. You can add a class to a heading to provide extra styles, or rework your heading styles entirely because they may not make sense in the first place if you are being tempted to use headings out of order.
Heading order solution
There must be only one h1 on any given page, as this corresponds to the page title or headline.
After that, the heading level represents the "scope" of the subsection. For instance, if you are working with an election results page showing the results of Democratic and Republican primaries in the state of Missouri, it would make sense to have the title of an individual office seat (such as governor) be an h2, while the Democratic and Republican primaries for that seat are each headed with an h3.
Our Washington Post article pages contain landmarks that screen reader users can quickly access via the rotor to jump around a page and hear different types of content.
We use the following landmarks as documented by W3C:
footer. We also use the article landmark defined by MDN to denote self-contained content such as an article or user-submitted comment.
In addition to the above, we can use
section tags to define other key regions on a page, but we need to include an
title attribute on these elements so screen readers know what they contain.
Similarly, if the same type of landmark is used on a page multiple times (for example, two
navs or two
asides), then we should add an
aria-label to each duplicate landmark to differentiate them.
Inspect one of our articles with the Chrome developer tools to find the landmarks. You can also open a screen reader rotor to view a list of landmarks.
The example code below demonstrates one way we can arrange landmarks on article pages. There are other possible arrangements. Your main focus in using the landmarks should be that they contain appropriate content. Otherwise screen reader users may be confused.
Labeling interactive elements
Our docs address the need for alt text when a reader cannot see an image.
aria-labelledby conventions are for interactive elements that are not images. See the ARIA guide for more context.
You might use aria-label on a clickable div on a page to clarify for the user its purpose:
Notice that the
aria-label attribute is passed a string value to be read by a screen reader.
aria-label can also be useful when you want to have two versions of the same text shown. For instance, in many tables on our live elections results pages we include abbreviations of certain words, such as "Unc." for "Uncontested," "Pct." for "Percent," etc.
We can use
aria-label to write text that is only seen by screen readers, while the standard component text remains seen by non-screen-reader users.
You might use
aria-labelledby to clarify for a screen reader the connection between an input field and its purpose:
Note that the
aria-labelledby is passed a string containing an element id or multiple ids separated by spaces. The text content of the elements with these ids is what will be read by the screen reader so that the user understands what each input field is for (in this case, "Billing Name" and "Billing Address").
There is also an
aria-describedby property meant to connect elements with relevant (but not essential information). This is not used as commonly, and
aria-labelledby should be used regardless of whether a value for
aria-describedby is also present on a given element.
Hyperlink text guidelines
It is important that hyperlink text is meaningful even out of context. This is because many screen reader users jump between links on a page without hearing the text surrounding each one. Read our screen reader guide for more info.
There are some key things to watch for when writing link text:
- Avoid using the URL as the link text.
- URLs are often read by screen readers in a disjointed manner, and they can also be confusing and less meaningful for sighted users.
- Keep link text concise, but don't sacrifice meaning. This speeds up the process of scanning links as a user, especially as a screen reader user.
- For example, "Subscribe" is better than "Subscribe for more content from us in the future."
- Don't include words like "link" or "click here" in your link text.
- This is redundant. Links should be evident in their styling and structure. If you feel the need to specify "click here," then your link probably isn't styled correctly for keyboard accessibility.
- Ensure each unique link has unique link text.
- If multiple links have different text but the same value, then users may waste their time clicking them all. This is a frustrating user experience.
- Similarly, if multiple links have the same text but go to different sites, then users may miss out because they assumed the links were the same.
Hiding content from screen readers
There are often ads on our products. When third-party ads are used, we don't have full control over their accessibility. For screen reader users, inaccessible ads hinder page navigation.
Our practice is to apply
aria-hidden="true" on our ad wrapper elements so that they are ignored by screen readers and thus do not clutter the page. The guide to ARIA attributes has more context.
aria-hidden="true" on non-ad content if and only if it is useless to screen readers (it is purely decorative or it is innaccessible content that already has a screen reader accessible alternative elsewhere on the page).
Content for screen readers only
Try searching "sr-only" on our Tachyons search page. You should find the following class:
This is a best practice for adding elements to a page that we want available only to screen reader users. For instance, we might have a table on a page and want a caption describing that table for screen readers without taking up space on the visible page layout.
You can add that caption to the table in the HTML and apply the sr-only class to ensure the text is available to screen readers but not visible.
A link with the
sr-only class applied will stay hidden to sighted users at all times, evem when it receives keyboard focus. This can cause confusion when sighted users navigate a page with keyboard controls. For this reason,
sr-only is generally not appropriate when working with interactive elements like links, buttons, etc. Use Visually Hidden (below) instead.
Visually Hidden component
See our Visually Hidden component docs for more information. It functions similarly to
sr-only, but they are not quite the same. For example, a Visually Hidden link will appear to sighted users when in focus. On the other hand, a link with the
sr-only class applied will stay hidden to sighted users at all times. For this reason,
sr-only is generally not appropriate when working with interactive elements like links, buttons, etc. Use Visually Hidden instead.
Non-English language support
Content in non-English languages, such as Arabic or Spanish, must have the lang="CODE" attribute set, where CODE is the language code such as “ar” for Arabic or “es” for Spanish. There’s a list of language codes.
Additionally, Arabic and some other languages are read right-to-left. This means we need to set an additional attribute in the HTML for Arabic text. Add dir="rtl to the DOM elements with lang="ar".
Below is an example of how this looks:
It is very important that this is done correctly. A screen reader user may
not hear content in non-English languages correctly if it is not tagged correctly.
For example, if Arabic is not tagged correctly, then it is not read by the built-in
MacOS & iOS screen reader VoiceOver. Instead, each character is read individually:
“Arabic character X, Arabic Character Y,” etc. VoiceOver also includes different
voices that pronounce the words from different languages. If
lang is not set on
non-English text, then VoiceOver will not use the correct voice.
The caption tag
caption tag is an important component of tables that is used by screen readers to provide an overview of a table when it is first reached. If we don't want the caption to be shown on the visible page (in some cases, we might), then we can hide it using the sr-only className.
The thead tag
For a table with only column headers, the
thead tag contains the headers for each column. Even though the tag is called
thead, the header elements must still be
th tags, not
td tags, in order for the screen reader to read the contents of the table correctly.
This is because screen readers read the header of the column for every cell within that column as a reminder to the reader of what is being read aloud. For instance, if our table contains vote totals and we have:
Then the screen reader will only read the headings once, at the top of the table, and the listener has to remember the order of (1) Biden, (2) Sanders and (3) Warren for the rest of their time reading the table, as they will only be read a bunch of state names and numbers sequentially.
On the contrary, if we have:
Then the screen reader user will hear "Votes for Warren - 3,000" when they get to the last cell in the table. This makes for a much more user-friendly experience, and this is why we should always make sure to use the
th tag in our
Alerting screen readers of live updates
aria-live is an attribute used to notify people using screen readers of dynamic changes in the content of a live region of a page. See the ARIA documentation on aria-live for more details.
While this attribute can serve a purpose in terms of accessibility, it should be used extremely cautiously. For instance, a screen reader user may be bothered repeatedly if
aria-live is applied for something like new comments on an article.
We almost always want to use
aria-live="polite" when we do use
aria-live. This makes it so that updates do not interrupt the screen reader user and instead waits til they idle.