Web Accessibility

PUBLISHED ON: Saturday, May 25, 2024

a11y → digital accessibility

Web accessibility is about designing and building websites and web apps that disabled people can interact with in a meaningful and equivalent way.

#

Disabilities

Visual impairment

Pain points:

  • Digital products that do not work with screen reader software
  • Mobile websites/apps without pinch to zoom
  • Complex graphs and charts differentiated by colors alone
  • Color contrasts that make it difficult to read text on the screen

Tools include:

  • Screen reader software
  • Screen magnification tools
  • Braille output devices.

Mobility impairments

Pain points:

Elements that are only designed to work with the use of a mouse.

Tools include:

  • Adaptive switches
  • Eye tracking devices
  • Mouth/head sticks
  • Speech input.

Hearing impairments

Pain points:

  • Audio content without text transcripts
  • Video with no synchronized captions

Tools include:

  • Hearing aids
  • Captions
  • Transcripts
  • Sign language.

Some deaf people say auto-captions are NOT better than nothing ❌

Cognitive impairment

Pain points:

  • Busy interfaces that make it overly complicated to focus on the task at hand
  • Big walls of words with little whitespace, justified text, and small or hard-to-read fonts.

Tools include:

  • Screen readers
  • Text highlighting
  • Text prediction
  • Abstractive summarization tools.

Seizure and vestibular disorders

Pain points:

  • Videos that autoplay
  • Extreme flashing or strobing of visual content
  • Parallax effects
  • Scroll-triggered animations.

Tools include:

  • Operating system settings to reduce motion.

In Windows, this setting is framed positively as Show animation, and is turned off. On Android, the setting Remove animations is turned on.**

Speech impairments

Pain points:

  • Voice-activated technology such as smart home devices and apps.

Tools include:

  • Augmentative and alternative communication (AAC) and speech-generating devices.

Key points to remember

  • 1.3 billion people self-identify as disabled globally.

  • Screen readers are commonly used to help disabled people on the web.

  • Filing a lawsuit is an effective way to enact change on the web.

#

Accessibility testing

WCAG → web content accessibility guidelines

WCAG is an international set of accessibility standards developed through the W3C, in cooperation with individuals and organizations. This provides a single shared standard for digital accessibility that meets the needs of individuals, organizations, and governments worldwide.

The WCAG guidelines have three levels of success criteria - A, AA, and AAA.

Success criteria:

Level Score
A 30
AA 20
AAA 28

Accessibility goals:

  • A → pass A level → 30
  • AA → pass A + AA levels → 50
  • AAA → pass A + AA + AAA levels → 78

#

Accessibility audit

Testing your digital product against an accessibility standard and conformance level is commonly referred to as an accessibility audit.

#

Accessibility principles

Principles of WCAG - Perceivable, Operable, Understandable, and Robust (POUR)

Perceivable

Users must be able to perceive all essential information on the screen, and it must be conveyed to multiple senses.

Examples

  • Adding text alternatives to all non-decorative images and essential icons.
  • Adding captions, transcripts, and audio descriptions to videos.
  • Ensuring color is not the only method of conveying meaning.

Operable

Users must be able to operate the digital product's interface. The interface cannot require interaction that a user cannot perform.

Examples

  • Adding keyboard and touchscreen support to all active elements.
  • Ensuring slideshows and videos have all of the necessary controls available.
  • Giving users enough time to fill out a form or a method to extend the time.

Understandable

Users must understand the information and the operation of the user interface.

Examples

  • Writing simply—don't use a complex word when a simple one will do.
  • Ensuring your digital product has predictable navigation.
  • Ensuring error messages are clear and easy to resolve.

Robust

Focusing on supporting assistive technologies and ensuring that, as devices and user agents evolve, the digital product remains accessible.

Examples

  • Testing keyboard-only navigation.
  • Testing with different screen reader technologies.
  • Ensuring all of the content and functionality can be accessed, regardless of device size or orientation.

#

ARIA and HTML

ARIA was first developed in 2008 by the Web Accessibility Initiative (WAI) group - a subset of W3C

Accessible Rich Internet Applications (ARIA)

Accessible Rich Internet Applications (ARIA) is a set of roles and attributes that define ways to make web content and web applications (especially those developed with JavaScript) more accessible to people with disabilities.

The accessibility tree

A tree of accessibility objects that assistive technology can query for attributes and properties and perform actions on.

The accessibility tree is created by the browser and based on the standard DOM tree. Like the DOM tree, the accessibility tree contains objects representing all the markup elements, attributes, and text nodes.

As the browser parses the content received, it builds the document object model (DOM) and the CSS object model (CSSOM). In addition to that, it also builds the accessibility tree which is used by assistive devices to parse and interpret content.

The accessibility tree is used by platform-specific accessibility APIs to provide a representation that assistive technologies can understand.

Main features of ARIA are:

  • roles -> define what an element is or does on the page or app
  • properties -> express characteristics or relationships to an object
  • states / values -> define the current conditions or data values associated with the element

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ARIA Example</title>
</head>
<body>
    <button id="menuButton" aria-haspopup="true" aria-expanded="false" aria-controls="menuList">
        Menu
    </button>
    <ul id="menuList" role="menu" aria-labelledby="menuButton" style="display: none;">
        <li role="menuitem"><a href="#home">Home</a></li>
        <li role="menuitem"><a href="#about">About</a></li>
        <li role="menuitem"><a href="#services">Services</a></li>
        <li role="menuitem"><a href="#contact">Contact</a></li>
    </ul>

    <script>
        document.getElementById('menuButton').addEventListener('click', function() {
            var menuList = document.getElementById('menuList');
            var isExpanded = this.getAttribute('aria-expanded') === 'true';
            
            if (isExpanded) {
                this.setAttribute('aria-expanded', 'false');
                menuList.style.display = 'none';
            } else {
                this.setAttribute('aria-expanded', 'true');
                menuList.style.display = 'block';
            }
        });
    </script>
</body>
</html>

Full accessibility tree in Chrome DevTools

On the frontend, the full tree is constructed by Chrome DevTools including ignored nodes and only prune them just before rendering the nodes. This is done because:

  • It makes it much simpler to handle node updates from the backend, since we have the same tree structure on both endpoints.
  • It ensures that all DOM nodes have a corresponding accessibility node.

#

When to use ARIA?

HTML tags with implicit role with an ARIA equivalent - <main>, <header>, <footer>, <aside>, <nav>

HTML attributes with implicit description with an ARIA equivalent - hidden, required

Rule 1: Don’t use ARIA


<!—- DON’T —->
<a role="button">Submit</a>

<!—- DO —->
<button>Submit</button>

Use semantic HTML elements (elements with implicit roles) instead of the role attribute whenever possible.

Rule 2: Don't add (unnecessary) ARIA to HTML


<!—- DON’T —->
<h2 role="tab">Heading tab</h2>

<!—- DO —->
<div role="tab"><h2>Heading tab</h2></div>

Rule 3: Always support keyboard navigation

tabindex="-1" can be used to remove an otherwise focusable element from the document’s tab order. The value of the negative integer makes no difference when declared.

tabindex="0" will allow an element to become focusable and become part of the document’s sequential tab order.

Avoid using tab indexes with positive integers whenever possible to prevent potential keyboard focus order issues.

Rule 4: Don't hide focusable elements

Don't add role= "presentation" or aria-hidden= "true" to elements that need to have focus—including elements with a tabindex= "0". As this will remove elements from the accessibiity tree and may lead to confusion among users.

Rule 5: Use accessible names for interactive elements

The purpose of an interactive element needs to be conveyed to a user before they know how to interact with it. This can be achieved by providing accessible name to elements.

Examples:

<button aria-label="Close">✖️</button>

<label id="nameLabel">Name:</label>
<input type="text" id="name" aria-labelledby="nameLabel">

<button aria-describedby="desc">Submit</button>
<div id="desc">Click this button to submit your information.</div>

<label for="email">Email:</label>
<input type="email" id="email" name="email">

Best Practices

  • Prefer native HTML elements and attributes for accessibility when possible, as they are widely supported and understood by assistive technologies.
  • Use ARIA attributes to supplement and enhance accessibility where native HTML is insufficient.
  • Ensure that the accessible names are concise and meaningful, providing clear context for the user.
  • Don’t override default HTML roles, reduce redundancy and be aware of unintended side effects.

#

Content Structure

Semantic HTML elements

Writing semantic HTML means using HTML elements to structure your content based on each element's meaning, not its appearance.


<header>
  <h1>Three words</h1>
  <nav>
    <a>one word</a>
    <a>one word</a>
    <a>one word</a>
    <a>one word</a>
  </nav>
</header>
<main>
  <header>
    <h1>five words</h1>
  </header>
  <section>
    <h2>three words</h2>
    <p>forty-six words</p>
    <p>forty-four words</p>
  </section>
  <section>
    <h2>seven words</h2>
    <p>sixty-eight words</p>
    <p>forty-four words</p>
  </section>
</main>
<footer>
  <p>five words</p>
</footer>

The top level <header>, <main>, <footer>, and <nav> are all landmarks. <header> and <footer> nested in other tags are considered as sections and not landmarks.

Tag Role
<main> main
<nav> navigation
<footer> contentInfo
<header> banner
<aside> complementary
<form> form
<section> region

Headings

Heading level order (<h1> through <h6>) is important to AT users as this is one of their primary ways to navigate through content.

Lists

Three types of HTML lists:

  • ordered <ol>
    • list item <li>
  • unordered <ul>
    • list item <li>
  • description <dl>
    • description term <dt>
    • definition <dd>

Tables

Layout tables must also be hidden from AT users with the ARIA presentation role or aria-hidden state .

The presentation role and its synonym none remove an element's implicit ARIA semantics from being exposed to the accessibility tree.

The aria-hidden state indicates whether the element is exposed to an accessibility API. It can be used to hide non-interactive content from the accessibility API.

❗ Do not use aria-hidden="true" on focusable elements.

aria-hidden="true should not be added when:

  • The HTML hidden attribute is present
  • The element or the element's ancestor is hidden with display: none
  • The element or the element's ancestor is hidden with visibility: hidden

Other useful table tags and attributes: <rowgroup>, <colgroup>, <caption> and scope

#

The Document

Page title

The HTML <title> element defines the content of the page or screen a user is about to experience. It's found in the <head> section of an HTML document and is equivalent to the <h1> or main topic of the page.

  • When writing page titles, it is best practice to front load the interior page or important content first, then add any preceding pages or information after.
  • Search engines typically display only the first 55–60 characters of a page title, so be sure to limit your total page title characters.

Language

Page Language

lang attributes sets the default language for the entire page. It is added to the <html> tag.

  • Use two-character ISO language codes for greater AT coverage.
  • Set lang to the primary language of the page. Multiple languages are not supported.

Section Language


<html lang="en">
  <body>...
    <div>
      <p>While traveling in Estonia this summer, I often asked,
        <span lang="et">"Kas sa räägid inglise keelt?"</span>
        when I met someone new.</p>
    </div>
  </body>
</html>

iFrames

<iframe> is used to host another HTML page or a third party's content within the page.

  • set the scrolling to "auto" or "yes"
  • each <iframe> with distinct content should include a title element inside the parent tag

<iframe title="Google Pixel - Lizzo in Real Tone"
  src="https://www.youtube.com/embed/3obixhGZ5ds"
  scrolling="auto">
</iframe>

#

Keyboard focus

Focus refers to which element on the screen currently receives input from the keyboard.

By default, focus order includes naturally focusable HTML elements, such as links, checkboxes, and text inputs. Naturally focusable HTML elements include built-in tab order support and basic keyboard event handling.

tabIndex

tabindex="-1" can be used to remove an otherwise focusable element from the document’s tab order. The value of the negative integer makes no difference when declared.

tabindex="0" will allow an element to become focusable and become part of the document’s sequential tab order.

Avoid using tab indexes with positive integers whenever possible to prevent potential keyboard focus order issues.

Skip links are especially helpful in long navigation menus, when a user may have already gone to the page of interest.


<body>
  <a href="#maincontent">Skip to main content</a>
  ...
  <main id="maincontent">
    <h1>Heading</h1>
    <p>This is the first paragraph</p>
  </main>
</body>

To address the concerns that a visible skip link can be intrusive, but still create a skip link that is useful for sighted keyboard users, we recommend creating a link that is hidden until the user navigates to it with a keyboard.

To be usable by all keyboard users, particularly sighted keyboard users, the link must:

  • be hidden by default
  • be accessible to keyboard navigation
  • become prominently visible when it is focused
  • properly set focus to the main content area when activated

To provide addition context to links, use aria-labelledby, aria-label or simply add text content to the <a> element.

Focus indicator

Focus indicator is important to let the user know where they are on the page.

❌ Don't do this:


a:focus {
  outline: none; /* don't do this! */
}

Focus Appearance (Level AAA)

When the keyboard focus indicator is visible, an area of the focus indicator meets all the following:

  1. is at least as large as the area of a 2 CSS pixel thick perimeter of the unfocused component or sub-component
  2. has a contrast ratio of at least 3:1 between the same pixels in the focused and unfocused states

Example:


/* on a white background */
a:focus {
  text-decoration: dotted underline 2px blue;
}

#

JavaScript

Trigger events

It's critical that you add keyboard support to your JavaScript actions, as it affects all of these users.

If an onClick() event is used on a semantic HTML element such as a <button> or <a>, it naturally includes both mouse and keyboard functionality. However, keyboard functionality is not automatically applied when an onClick() event is added to a non-semantic element, such as a generic <div>.

Page titles

For SPAs, document.title value can be updated manually or using dynamic content or with a helper package.

Dynamic content

Setting content dynamically using innerHTML or setting CSS using setAttribute("style", ...).

Possible misuse Correct use
Render large chunks of non-semantic HTML Render smaller pieces of semantic HTML
Not allowing time for dynamic content to be recognized by assistive technology Using a setTimeout() time delay to allow users to hear the full message
Applying style attributes for onFocus() dynamically Use :focus for the related elements in your CSS stylesheet
Applying inline styles may cause user stylesheets to not be read properly Keep your styles in CSS files to keep the consistency of the theme
Creating very large JavaScript files that slow down overall site performance Use less JavaScript. You may be able to perform similar functions in CSS (such as animations or sticky navigation), which parse faster and are more performant

Focus management

Component level

Create keyboard traps when a component's focus is not properly managed

Example:

When a keyboard-only user encounters a modal, the user should be able to tab between the actionable elements of the modal, but they should never be allowed outside of the modal without explicitly dismissing it. JavaScript is essential to properly trapping this focus.

Page level

Maintain focus during user navigation from page-to-page.

To achieve this:

  • Place focus on the main container with an aria-live announcement.
  • Put the focus back to a link to skip to the main content.
  • Move the focus to the top-level heading of the new page.

State management

Component level

Example: aria-expanded, aria-pressed

Page level

ARIA live regions provide a way to programmatically expose dynamic content changes in a way that can be announced by assistive technologies.

This is done using aria-live=POLITENESS_SETTING where POLITENESS_SETTING has the possible values of off, polite or assertive.

Normally, only aria-live="polite" is used.

aria-live="polite" indicates that the screen reader should wait until the user is idle before presenting updates to the user.

When an element has aria-live="off" (or has a role with this implicit value, such as role="marquee" or role="timer"), changes to the element's content are only supposed to be announced when focus is on, or inside, the element.

Roles with implicit live region attributes

log, status, alert, progressbar, marquee, timer

For reference: MDN Link

Other live region attributes
  1. aria-atomic: The aria-atomic=BOOLEAN is used to set whether or not the screen reader should always present the live region as a whole, even if only part of the region changes. The default setting is false.
  2. aria-relevant: The aria-relevant=[LIST_OF_CHANGES] is used to set what types of changes are relevant to a live region. The possible settings are one or more of: additions, removals, text, all. The default setting is: additions text.

#

References