Photo by Hannah Busing on Unsplash
These are my notes from the excellent two Frontendmasters' courses about accessibility, by Jon Kuperman and Marcy Sutton.
Accessibility myth-busting
- Screen readers use JS.
- People use keyboards.
- The days of "screen-reader" skip links and other "offscreen" only skips are over, they should be made visible too.
- Navigating by voice is a big part of a11y.
- Browsers cannot detect if someone is using a screen reader.
Overlapping areas
- SEO. a11y doesn't affect the ranking but headers do, so headers help both a11y and SEO.
- Add links are good for screen readers.
- Performance. Faster load faster interaction.
- Security. No a11y means a security flaw, because people cannot do it independently.
- Business growth. The more a11y the more people can use your website.
Standards
-
WCAG (Web Content Accessibility Group). A standard set of criteria for measuring a11y. The current version is
2.2
(here). There is a looming 3.0 version. It is developed in open source in Github. Provides 3 conformance levels: A (lowest), AA (mid-range), and AAA (highest). -
Aria
(Accessible Rich Internet Applications) is a w3 spec (same group as CSS and HTML) and it is a set of accessibility helpers that you can apply to your HTML. The current ARIA version is1.2
(here) and also developed in the open, in Github. Other ARIA-related non-normative documents (informative): ARIA in HTML and Using ARIA. - WebAIM - Web Accessibility In Mind. They provide a checklist. It is not an official spec but rather a way to make the WCAG specs more digestible.
Screen readers
- Type of
AT
(Assistive Technology), both software and hardware. They convert text and graphic images to speech or Braille output. - iPhones and Macs have screen readers built in (VoiceOver). On Windows, users can use the built-in screen reader
Narrator
or installNVDA
orJAWS
. - There are many combinations and we can't test them all.
WebAIM
runs a survey every couple of years where you can see the most popular screen-readers for each platform. You can focus on these. - VoiceOver keyboard cheatsheet.
- NVDA for Windows (free), Chrome screen reader, Voiceover for Mac.
- Images.
alternative text
. The screen reader will read the file name if it doesn't find analt text
. Alt text will override this behavior.alt=""
is empty alt text and the screen reader will not read it. This is useful if you have decorative images. Screen readers will ignore images in a CSS background. The alt text should be brief and descriptive. Lacking alt text is one of the top 5 a11y issues. Alt decision tree will help you decide if and what to write in the alt text. - X-browser testing - https://assistivlabs.com/ can help.
- Audio. Needs captions.
Testing / Debugging
- Steps to take:
- STEP ONE: Tab key to navigate: can you reach and operate every interactive control? Can you see where your focus point is on the screen? Do you get trapped anywhere that you can't escape (see keyboard trapping below)? Can you use other common keys like arrows, ESC, key, and space key?
- STEP TWO: Open a browser devtool extension like Axa. Prioritise violations over best practices.
- STEP THREE: Zoom the browser to at least 200% (see reflow below).
- STEP FOUR: Test light and dark mode. Ensure animation and motion can be turned off with Reduced Motion (see below).
- STEP FIVE: Run a screen reader.
- STEP SIX: Make note of missing transcripts or captions and other alternative content. Ensure media players and pages can accommodate this content.
- Linters and dev tools: built in the browser, Chrome lighthouse, browser extensions, linters,
Accessibility
tab inElements
tab in Chrome.
Accessible HTML
- Basics always apply: HTML needs to be
valid
,well structured
, andusing as many defaults as possible
. -
WELL STRUCTURED
: structural semantics is very helpful in screen readers and other reader modes. Notdiv
s all over the place. -
AS MANY DEFAULTS AS POSSIBLE
. Try to use as many defaults as possible because they come with a lot of a11y behavior for free. - You can do a lot by using semantic HTML.
<aside>
,<footer>
and<header>
don't have functionality but have semantic meaning. Others like<button>
,<input>
, and<textarea>
provide a lot of built-in functionality. It is important to avoid generic HTML elements when more dedicated built-in elements exist. Avoid "div soup" or "divitis". - HEADERS: use
h1-h6
headings to create a page outline. Style them with CSS. Avoid theHTML5 heading algorithm
as it was not implemented for Assistive Tech. Use a heading based on what the content is, not how the content should look like. CSS doesn't influence screen readers. You should always use the appropriate heading and style it only if you ever need to. - LANDMARK ELEMENTS:
nav
,main
,section
,header
, etc. - LISTS: they are great, a screen reader will say "5 items", or whatever. Don't add other types of descendants to a list element.
- FORMS: very powerful elements, like
<form>
,<fieldset>
and<legend>
. Labels are essential for inputs/textareas/etc in Assistive Technology (AT). Explicit labels usefor
andid
. Implicit labels wrap an input. Only certain elements can be labeled. - HTML labels. Explicit (using
for
attribute) or implicit (nesting input field) is the way to go. No label withdiv
orp
. Labels work for "labelable" items, such as:<button>
,<input>
,<keygen>
(deprecated),<meter>
,<output>
,<progress>
,<select>
and<textarea>
. If you need to label an element not on that list, usearia-label
instead. -
role
. You can use an ARIA role to indicate to the screen reader that thediv
(or whatever other than a button) is being used as a button. Example:
<div role="button" onClick="() => alert('hey')">Click me</div>
^ This will tell the screen reader that the div can be clicked. But this won't let the div be focusable, so we have something called tab-index
. That means that it can be focused with the keyboard. But if you are a keyboard-only user, you won't be able to click on the element. That's why we have onKeyUp
(you can get precise and only listed to Enter or Spacebar. The last thing, we need an aria-label
to label the element.
- BUTTONS AND LINKS. HTML buttons give a lot of behavior for free: focusability, built-in-role, and keyboard click events. Links need an
href
to be accessible. Buttons toggle things and links navigate - use them appropriately. - DETAILS AND SUMMARY. Are built-in accordion-style disclosure widgets.
- SETTING LANGUAGE.
<html lang="en">
. If language is dynamic, it can be set on a template. Element level vs page level language:
<html lang="en">
<body>
<p lang="fr"></p>
</body>
</html>
ARIA
-
ARIA
stands forAccessible Rich Internet Applications
and it's a way to add accessibility information to your apps. As of winter 2023, the current version is1.2
(specs here and MDN docs here). - ARIA and HTML work great together. Built-in roles for buttons, links, etc. (implicit roles) vs the ones we add with ARIA (bolt-on).
- The major categories of ARIA are
roles
,states
, andproperties
. i.e.role="button"
oraria-hidden="true"
. - ROLES. Many HTML elements have roles built-in, such as
<button>
or<main>
. They can also be bolted on to override the default semantics of an element.<button>
has the implicitbutton
role.<div role="button">
has the explicit button role. You should use the native HTML element with a role built-in. - ARIA attributes can be used as selectors in CSS. i.e. [role="checkbox"][aria-disabled="true"] {}
- You can bolt-on accessible names and descriptions using explicit ARIA attributes like
aria-label
,aria-labelledby
, andaria-describedby
. - LIVE REGIONS. It allows the screen reader to "listen" to content change in the app and read it. i.e. uber app after a ride has been booked when it changes to "looking for a driver", "driver found", "driver is here", etc. This is done with
aria-live
and it has two values:assertive
(interrupts reading to read the update) orpolite
, which will wait for the screen reader to finish reading. If it is off it will not read the update. -
<label>
is great but it only covers some elements. For the rest, you can use the following aria tools:aria-label
,aria-labelledby
, andaria-describedby
. -
aria-label
andaria-labelledby
do the same but the difference is similar to the explicit and implicit label:labelledby
refers to anid
of some previous element. That element would probably have to be visually hidden or sth.aria-describedby
is about description, extended information that the user may need. - ARIA roles, states, and properties.
Focus management
- Keyboard shortcuts. You can build them for your app to help folks who are keyboard users only.
- Skip links. Allows you to go to main content, you can see examples in github.com or The New York Times. Create a visually hidden anchor with the body "skip to content", prepend it to the body, and give it a focus state in CSS.
- Tab navigation.
tab
andshift-tab
to navigate forth and back in a website. Tabable elements include<a>
,<button>
,<input>
,<select>
,<textarea>
,<iframe>
. To make a non-tabable element tabable you can use thetab-index
attribute to achieve so. Negative means that the element is not reachable via sequential keyboard navigation. value0
means it is reached by sequential tabbing and positive means that it takes priority. MDN docs here. - Active element. To know which one it is (in case it is hidden or you cannot find it) you can use
document.body.addEventListener('focusin', () => console.log(document.activeElement));
in your browser console. It will print the element that has focus (active element API). -
Keyboard trapping
. Focus only on a subset of elements. The user's keyboard focus would cycle through the elements until they complete a task or close that layer (like in an accessible modal). Level A WCAG dictates that there should be no keyboard traps. React-aria can do it for you. Also, existing design systems libraries (i.e. Chakra UI) normally have accessibility incorporated into their components. - Keyboard shortcuts can be helpful.
Visual considerations
Color contrast
- Tools you can use: Lighthouse audit, WebAIM contrast checker for the design phase, Chrome dev tools (more info here).
- Colors and forms. Validation errors with red/green may not work for people with disabilities. Color only is not enough, you should put some text or label.
- Visual impairments. Firefox extension called NoCoffee. Keeping things together helps because people may have a narrow vision field.
- Setting the language. In the top level
html
and for certain text that deviates. - Fix markup errors. You can use https://validator.w3.org/.
Reflow
- Content can be presented without loss of information or functionality, and without requiring scrolling in two dimensions for. Specs can be found here.
Reduced motion
-
prefers-reduced-motion
. You can access the motion a11y settings from the system to change your code, like CSS animation (i.e. from pulsing to something softer).
Color preference
- Same for the system color preference, dark or light. You can access it with:
@media (prefers-color-scheme: dark) {
.main {
background: black;
color: white;
}
}
@media (prefers-color-scheme: light) {
.main {
background: white;
color: black;
}
}
Tooling
Linters
Accessible Design Systems
Accessibility Developer Tools
- To do audits. Deque and Google's Lighthouse.
More resources
- https://learn-a11y.netlify.app/resources/ (Jon's course website)
- https://web-accessibility-v3.vercel.app/ (Marcy's course website)