Accessibility for the web
Tags: a11y, beginners, frontend
Published: 2024-02-25 17:48:44

_Photo by [Hannah Busing](https://unsplash.com/@hannahbusing?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash) on [Unsplash](https://unsplash.com/photos/person-in-red-sweater-holding-babys-hand-Zyx1bK9mqmA?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash)_

These are my notes from the excellent two Frontendmasters' courses about accessibility, by [Jon Kuperman](https://frontendmasters.com/courses/accessibility-v2/) and [Marcy Sutton](https://frontendmasters.com/courses/react-accessibility/).

#### 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](https://www.w3.org/WAI/standards-guidelines/wcag/) (Web Content Accessibility Group). A standard set of criteria for measuring a11y. The current version is `2.2` ([here](https://www.w3.org/TR/WCAG22/)). 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 is `1.2` ([here](https://www.w3.org/TR/wai-aria-1.2/)) and also developed in the open, in Github. Other ARIA-related non-normative documents (informative): [ARIA in HTML](https://www.w3.org/TR/html-aria/) and [Using ARIA](https://www.w3.org/TR/using-aria/).
- [WebAIM](https://webaim.org/) - Web Accessibility In Mind. They provide a [checklist](https://webaim.org/standards/wcag/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 install `NVDA` or `JAWS`.
- 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](https://dequeuniversity.com/screenreaders/voiceover-keyboard-shortcuts).
- [NVDA](https://www.nvaccess.org/) 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 an `alt 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](https://www.w3.org/WAI/tutorials/images/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](https://web-accessibility-v3.vercel.app/topics/accessibility-debugging/linters-and-devtools#browser-extensions), [linters](https://web-accessibility-v3.vercel.app/topics/accessibility-debugging/linters-and-devtools#eslint-and-other-text-editor-plugins), `Accessibility` tab in `Elements` tab in Chrome.

#### Accessible HTML

- Basics always apply: HTML needs to be `valid`, `well structured`, and `using as many defaults as possible`.
- `WELL STRUCTURED`: structural semantics is very helpful in screen readers and other reader modes. Not `div`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 the `HTML5 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 use `for` and `id`. 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 with `div` or `p`. 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, use `aria-label` instead.
- `role`. You can use an ARIA role to indicate to the screen reader that the `div` (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 for `Accessible Rich Internet Applications` and it's a way to add accessibility information to your apps. As of winter 2023, the current version is `1.2` (specs [here](https://www.w3.org/TR/wai-aria-1.2/) and MDN docs [here](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA)).
- 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`, and `properties`. i.e. `role="button"` or `aria-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 implicit `button` 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`, and `aria-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) or `polite`, 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`, and `aria-describedby`. 
- `aria-label` and `aria-labelledby` do the same but the difference is similar to the explicit and implicit label: `labelledby` refers to an `id` 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](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques).

#### 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` and `shift-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 the `tab-index` attribute to achieve so. Negative means that the element is not reachable via sequential keyboard navigation. value `0` means it is reached by sequential tabbing and positive means that it takes priority. MDN docs [here](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex).
- 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](https://react-spectrum.adobe.com/react-aria/index.html) 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](https://webaim.org/resources/contrastchecker/) for the design phase, Chrome dev tools (more info [here](https://webaim.org/articles/contrast/devtools)).
- 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](https://addons.mozilla.org/en-US/firefox/addon/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/](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](https://www.w3.org/TR/WCAG22/#reflow).

##### 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

- [https://www.npmjs.com/package/eslint-plugin-jsx-a11y](https://www.npmjs.com/package/eslint-plugin-jsx-a11y) for React

##### Accessible Design Systems

- [Adobe's React Spectrum](https://react-spectrum.adobe.com/react-spectrum/)
- [Google Material Design](https://m3.material.io/)

##### Accessibility Developer Tools

- To do audits. [Deque](https://chromewebstore.google.com/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US) and [Google's Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/).

#### More resources

- https://learn-a11y.netlify.app/resources/ (Jon's course website)
- https://web-accessibility-v3.vercel.app/ (Marcy's course website)