/learning-a11y

Learning accessibility (a11y)

Primary LanguageHTML

Learning Web Accessibility (a11y)

Just one of the things I'm learning. https://github.com/hchiam/learning

This repo's link is easier to remember/type. It serves as a redirect to find this repo faster:

https://github.com/hchiam/web-accessibility-course-notes

Start with the above link. Extra notes may be added to this repo too.

Deque prep course for IAAP WAS: https://dequeuniversity.com/curriculum/packages/iaap-was

Key things

  1. Automate what you can: WAVE or axe DevTools for Firefox or lighthouse or axe DevTools for Chrome or axe-linter VSCode extension.
  2. Test realistically: screen readers + keyboard. Besides mouse and touch. And mobile.
  3. Tab. Shift+Tab. Enter. (And screen reader + arrow keys.)
  4. Resize page zoom to look for text reflow/overflow bugs.
  5. Checklist/report generator: WCAG-EM
  6. WCAG checklist: https://www.a11yproject.com/checklist or https://www.w3.org/WAI/WCAG22/quickref/?versions=2.1 although you might just want to use the WCAG-EM instead anyways for reporting

My summary:

  • P = Perceivable = can see/hear/feel (like captions).
  • O = Operable = can use (like element focusability + keyboard + time + recovery).
  • U = Understandable = can get meaning (like labels + layout familiarity + meaningful error messages), basically need P and O first before U.
  • R = Robust = is flexible/cross-compatible (like mobile versus desktop).

Some a11y-related GitHub repos

Some GitHub projects I updated to be more accessible

Some a11y-related CodePens

The 8 topics are:

  1. Help users understand what things are and how to use them.
  2. Help users find what they need.
  3. Use clear content (text, images and media).
  4. Help users avoid mistakes.
  5. Help users focus.
  6. Ensure processes do not rely on memory.
  7. Provide help and support.
  8. Support adaptation and personalization.

More notes:

More notes (click to expand)

Random note

Creating instances of elements in JS instead of hidden in HTML will work for getting HTML5 elements to work in IE <= 8 (need instance created first for some reason).

Literally paste the following Internet Explorer conditional comment:

<!--[if lt IE 9]>
  <script>
    var e = (
      "abbr,article,aside,audio,bdi,canvas,datalist,details,dialog," +
      "figcaption,figure,footer,header,keygen,mark,menu,meter,main,nav,output," +
      "progress,rp,ruby,rt,section,source,summary,time,track,video,wbr"
    ).split(",");
    for (var i = 0; i < e.length; i++) {
      document.createElement(e[i]);
    }
  </script>
<![endif]-->

Caption file formats

Basic

Advanced

Media Accessibility Decision Matrix (WCAG Level AA "Must"s)

Reference: https://codepen.io/cerovac/full/MWKVVYj

Consider: https://ableplayer.github.io/ableplayer/

Media Captions Transcript Audio Descriptions Sign Language
Pre-recorded Multimedia Must (C) Must (AD)
Pre-recorded Video-only Must (AD)
Pre-recorded Audio-only Must (T)
Live Multimedia Must (C)
Live Video-only
Live Audio-only

"CAST": C = Captions. AD = Audio Descriptions. T = Transcript. S = Sign Language.

Mnemonic, version 1: Just what's AA "Must":

  • Pre-recorded Multimedia = CAD.
  • Pre-recorded Video-only = AD.
  • Pre-recorded Audio-only = T.
  • Live Multimedia = C.

Mnemonic, version 2: Just letters:

  • PMCAD. PVAD. PAT. LMC.

Mnemonic, version 3: Semantic overlap:

  • Pre-recorded has higher requirements than not pre-recorded.
  • Except Multimedia always requires C (whether pre-recorded or not).
  • Pre-recorded requires AD if has Video (so Multimedia counts). "See --> Hear".
  • Pre-recorded requires T only if Audio-only. "Hear --> See". (Caption naturally doesn't make sense in this case, so must use T.)

Mnemonic, version 4: Semantic overlap, reworked: "Pre-recorded + Multi, Video then AD, Audio then C".

  • "Pre-recorded + Multi": Only Pre-recorded things have "Must", except Multimedia also always requires Captions (whether pre-recorded or live).
  • "If Video then AD": Pre-recorded Video or Multi-media (which contains video) require Audio Descriptions.
  • "If Audio then C, except T for Audio-only": Pre-recorded Audio requires Captions, except Audio-only requires Transcript instead (which is similar to Captions), because there's no video to sync the Captions with.

Note: It's better to always include a transcript to give access to people who are deafblind, but it also helps with text searches, or if prefer reading quickly over watching.

Note: Some people understand a sign language better than captions or transcripts.

Notes on parallax

  • Parallax scrolling can decrease usability or even cause dizziness in some people (e.g. those who have vestibular disorders).
  • CSS media query prefers-reduced-motion is currently not universally supported, so consider a including a setting toggle for now, as long as functionality/access is preserved without the removed animations.

Notes on mouse input

  • Up event (not on down event) = cancellable before release.
  • Consider click target size. (For mobile: 44px squared or 48px squared min.)
  • A click event is accessible to mouse and touch and keyboard! (As opposed to onmouseup or ontouchend or onkeyup.)

Notes on focus

  • System-wide keyboard accessibility: Mac has a setting that lets you tab to all controls, not just inputs.
  • Move focus to new content only if triggered by user (example: modal), otherwise it's disorienting (example: screen reader users tend to explore forms before filling them out, triggering blur).
  • Move focus to next logical element if element removed (example: closing modal). This means you need to maintain the previously-focused element in memory somehow. (Otherwise focus returns to top of page - really bad.) Also make sure the re-focused element announces something so the user knows what they teleported to.
  • Widget usage instructions with a popup tooltip + aria-label are nice to have when focusing on a custom widget or when users aren't familiar with the standard ARIA keyboard interaction patterns for a widget.
  • Make infinite scrolling the last element on the page, or let users "escape", or let users decide to load more.
  • You can use tabindex="-1" on text to let JS focus it, otherwise tabindex="0" might confuse users when they happen to focus it with Tab (when they expect the usual focusable elements).

Notes on touch input

  • Make sure gestures can also be alternatively done with taps (for people with mobility/dexterity issues having difficulty performing touch gestures).
  • A click event is accessible to mouse and touch and keyboard! (As opposed to onmouseup or ontouchend or onkeyup.)

Notes on forms

  • aria-describedby won't work on <fieldset> or <legend>, so avoid having non-label/non-focusable text in the middle of a form (users likely will tab and miss the text), and instead put the text before the form, or associate the text with one or more of the inputs with aria-describedby on them.
  • Make sure instructions and labels are next to their related inputs (both visual and cognitive effects). Otherwise they can be hidden/shown with a button, instead of making the text small.
  • Tell screen reader users of required fields with aria-required="true". The alternative is the <... required> attribute, which adds browser behaviour, but does so inconsistently, and may conflict with your custom form validation behaviours. Either way, also include visual indicators for sighted users.
  • aria-invalid="true" and aria-describedby="error_description" on the inputs
  • <a href="#email">Go to the first field with an error to fix it.</a>
  • autocomplete="current-password" - see https://www.w3.org/TR/WCAG21/#input-purposes
  • Example: https://dequeuniversity.com/assets/html/module-forms/progressive/good/index.html
  • Custom form element: make sure it has a Name, Role, and Attribute (i.e. Label, Role, and State.). Anything that can't be communicated via those things should go into an aria-live region.
  • Confirm before submitting (and enable fixing).
  • Confirm after submitting (set focus after page load to avoid issues with parsing timing).
  • Consider indicating form success/error in <title> = first thing user hears on new page.
  • Consider aria-live with 2-second debounce for "password strength messages". (On blur won't work because the new focus will likely get announced instead.)
  • Tab, Shift + Tab, Enter/Spacebar, arrow keys, (for <select>:) Alt/Option + Down arrow and then arrow keys and then Enter

Notes on screen readers

  • Common screen readers and common keyboard shortcuts for them.

  • Test dynamic content with at least 2 screen readers, since there can be big differences in how they handle dynamic content.

  • suggested screen reader + browser/device combos:

    • JAWS with Chrome/IE
    • NVDA with Firefox/Chrome
    • Narrator with Edge
    • VoiceOver with Safari (macOS)
    • VoiceOver with Safari (iOS)
    • TalkBack with Chrome (Android)
  • Most screen readers can automatically or manually switch between different modes depending on context, to let you type extra or different commands to do things useful in context: document/reading mode, table mode, forms mode, app mode, virtual cursor mode, focus mode, etc. For example, you wouldn't want the next header key shortcut H to trigger when typing the letter H into a form input. Modes switch automatically in VoiceOver.

  • JAWS seems to cover the most browsers, including IE. It also has cursor options. But JAWS is expensive. So NVDA seems best to me to use, especially with the rise in popularity of NVDA.

  • JAWS works well with Chrome, Firefox, Edge, and IE.

  • NVDA works well with Chrome, Firefox, and Edge. But NVDA has recently gained more popularity than JAWS (2019 screen reader survey).

  • Narrator works best with Edge. It also has a Developer mode that lets you see only the things currently exposed to the screen reader.

  • VoiceOver works best with Safari.

  • ChromeVox works on Chrome and ChromeOS/Chromebooks.

  • Consider telling users that content is still loading with things like alt="Content loading" (but don't go overboard with aria-live unless it's a really slow process).

  • Using visibility: hidden;, display: none;, or attribute hidden will hide the element visually but also hides it from screen readers, so you'll need to resort to clipping or positioning or aria-label to expose it to screen readers only. See my notes on hiding elements visually and/or in the Accessibility Tree.

  • /* source: https://webaim.org/techniques/css/invisiblecontent/ */
    .sr-only {
      /* screen-reader-only: */
      clip: rect(1px, 1px, 1px, 1px);
      clip-path: inset(50%);
      height: 1px;
      width: 1px;
      margin: -1px;
      overflow: hidden;
      padding: 0;
      position: absolute;
    }

Notes on new content or SPAs (Single-Page Apps)

  • "Please wait" message (or new content for SPAs): focus on it or aria-live it. Plan some shared method to manage focus or to announce link/route events. Consider intentional pause before resetting focus, in case the delay is shorter than expected (consider "Please wait. Here's some content that already loaded but sounds like part of the interstitial message.") and to avoid timing issues.

  • In VoiceOver, focus needs to be (re)sent to an element for it to be announced, even if its text changed (so temporarily send focus to an empty container and back).

    event.preventDefault();
    
    hiddenEmptyContainerForTemporaryFocus.focus(); // <--- to enable announcing the later-focused element in case it happens to be the same element but updated
    
    oldContent.empty();
    populateNewContent();
    
    updateBrowserHistory(newUrl, newTitle); // <--- for SPAs
    
    var delayForIOS = 1000;
    setTimeout(() => {
      newHeading.focus(); // <--- to orient the teleported user
    }, delayForIOS);
  • For SPA links: remember to systematically update browser history so the back button works.

    function updateBrowserHistory(newUrl, newTitle) {
      history.pushState(
        {
          url: newUrl,
          title: newTitle,
        },
        newTitle,
        newUrl
      );
    }
    $(window).on("popstate", function (event) {
      var state = event.originalEvent.state;
      var wasBackOrForwardHit = state !== null;
      if (wasBackOrForwardHit) {
        oldContent.empty();
        document.title = state.title; // screen reader will read <title> first (good place for status update)
        populateNewContent();
        var delayForIOS = 1000;
        setTimeout(() => {
          newHeading.focus();
        }, delayForIOS);
      }
    });

Notes on accessible name calculation algorithm

Basically

  1. aria-labelledby (Note: this is NOT aria-labelledby.)
  2. aria-label
  3. text <-- (but for implementation, go for this option first)
  4. (title but only kinda works for some users)

Fun facts

  • Note that description !== label.

  • Label = replaces the element's original text.

  • Description = (with a pause) announced after the computed label, as extra info.

  • aria-labelledby="can have multiple IDs as labels"

  • Keep in mind that aria-label is not consistently supported for some non-focusable elements, screen reader versions/modes, or browser versions.

  • Use aria-label on the search box, since it's usually focused before the button, otherwise it's not immediately obvious what the input is for:

    <form action="#" role="search">
      <input aria-label="Search" name="search" type="search">
      <input type="submit" value="Search">
    </form>

Note on visual disabilities

Note on physical impairments

  • note: let users disable/customize single-key keyboard shortcuts to avoid voice-only users accidentally triggering multiple keyboard shortcuts with one word of a voice command (aside from self: getting surprised by keyboard shortcuts I didn't expect to exist or want to trigger) - https://learning.edx.org/course/course-v1:W3Cx+WAI0.1x+3T2019/home - take-away: flexibility!

Notes on screen magnification

  • from https://learning.edx.org/course/course-v1:W3Cx+WAI0.1x+3T2019/home
    • screen changes in other parts of the page should still be notified to screen magnification users
    • key content should not be contained in hover states or tooltips, especially if it's hard for screen magnification users to see on-screen
    • position priority content where users expect it

Note on page titles (browser tab title)

Note on disabled buttons and inputs

  • css-tricks recommends aria-disabled="true" and JS to prevent clicks by pointers or keyboards
  • but I'd consider this jQuery helper function I wrote: (demo of disableEditing)
    /**
    Don't disable submit button (screenreader user: unaware skipped; sighted user: must realize must hunt for errors).  
    Don't disable inputs like textareas or select dropdowns: screen readers can't tab to it to read the value!
    TODO: make this work for radios and checkboxes
    */
    function disableEditing(scope, isEditDisabled) {
        const elements = $(scope.is(':input') ? scope : $()).add(scope.find(':input'));
        elements
            .removeAttr('disabled').prop('disabled', false) // to enable tab focus
            .prop('readonly', isEditDisabled) // to disable edits without disabling focus
            .attr('edit-disabled', ''); // to disable clicks
        elements.find('option')
            .toggle(!isEditDisabled); // to prevent showing and changing select dropdown options
    }
    var scope = $('.modal:visible :input:disabled');
    editDisabled(scope, true);

Notes on ARIA roles

  • Ctrl+F or Cmd+F for ARIA roles and ARIA attributes in this Role Data Model

    • On top: ARIA roles. Example: role="checkbox".
    • On bottom: ARIA attributes. Example: aria-checked="true". (Link: descriptions of ARIA attributes)
    • (Note: some roles are "abstract" and can't actually be used in the code.)
  • Only use ARIA roles+attributes if you need to. Better to use native built-ins.

  • For modals, you'll likely need to put role="document" to wrap the text content like <p> etc. when the modal container has role="dialog". This is because role="dialog" turns some screen readers to application mode (basically inherits role="application"), which ignores text that doesn't have tabindex="0" set, so you may need role="document" to turn those screen readers back to document mode. <div role="dialog"><div role="document">.

  • role="application" gives developers more freedom but also more responsibility. It turns off most page navigation features, which lets you define custom keyboard logic, but now you might need to re-implement a bunch of things.

    • Notably, application mode does not turn off the normal behaviour of: Tab for focus, Enter/Return, space bar, or arrow keys (on selects or radios).

    • So you sometimes might need to do this: (unless you set tabindex="0" on text elements, which may mislead users to think they're on buttons)

    <div role="application">
      <div role="document"></div>
    </div>
    • role="dialog" and role="alertdialog" and role="tablist" automatically trigger application mode and hence keyboard limitations/freedoms.
  • You can use role="math" and aria-label="(description of the math expression)" on a <div> that wraps MathML markup with a <math> element, but MathML isn't universally supported. Or just use MathJax, which also happens to be able to help with MathML markup support for all browsers.

  • aria-busy="true" if you want to suppress suppress aria-live region announcements (e.g. page load).

  • tabs:

    • role="tablist" contains role="tab" which controls display of role="tabpanel"
    • aria-selected="true" the current tab (role="tab")

Deque ARIA patterns

  1. Alert
  2. Current page: Button
  3. Button (Toggle)
  4. Carousel (based on a tabpanel)
  5. Checkbox
  6. Checkbox (Tri-State)
  7. Dialog (Simple Dialog)
  8. Dialog (Simple Alert Dialog)
  9. Dialog (Message Dialog)
  10. Dialog (Message Alert Dialog)
  11. Expand/Collapse
  12. Expand/Collapse (based on Details/Summary)
  13. Link
  14. Navigation (Hierarchical) with Expand/Collapse
  15. Predictive Text
  16. Progress Bar (Bounded)
  17. Progress Bar (Unbounded)
  18. Radio and Radio Group
  19. Slider
  20. Slider (Multirange)
  21. Tabpanel
  22. Table (Responsive, Collapsible)
  23. Table (Sortable)
  24. Tooltip
  25. Tooltip Dialog
  26. Tree View

Deque ARIA patterns - Imports

Deque ARIA patterns - Examples

Analogy for Accessibility Tree element properties

  • Name: aria-label="Howard"
  • Description: aria-description="likes learning" or aria-describedby="description_container_id"
  • Role: role="software developer"
  • Property: start="9" end="5" (and value)
  • Relationship: aria-owns="this GitHub account"
  • State: aria-selected="true"

WCAG notes

  • "PGS": 4 Principles --> Guidelines --> SC (Success criteria) --> A, AA, AAA.

WCAG-EM notes

  • WCAG-EM = website accessibility conformance evaluation methodology

  • WCAG-EM procedure

  • WCAG-EM report generator

    • Very helpful form! Reminders of all the steps! Auto-adjusts field prompts depending on selected A/AA/AAA level!
    • Steps: "S.E.S.A.R.":
      1. Scope (prioritize, images, forms, tables, widgets, consider to-be-commonly-used templates)
      2. Explore (automated test to cover 30%, then screen reader + browser + device combos)
      3. Sample
      4. Audit sample
      5. Report (say what bug, where, what expect, what breaks for who, how impactful on user+/business+/design-, how repro, visual, how might fix, how easy to fix) = faster to triage and actually fix
  • another way to break down the 9 things in the Report:

    1. what
    2. where
    3. who
    4. what expect
    5. how impactful (user, business, design)
    6. how might fix
    7. how easy fix
    8. visual
    9. how repro

Various terms to know

Test yourself:

  • a11y
  • UX
  • POUR
  • W3C
  • WCAG
  • WAI-ARIA
  • ATAG
  • WCAG-EM
  • A, AA, AAA
  • ADA
  • Section 508
  • WCAG 2.1
  • CVAA
  • AODA
  • EN 301 549
  • IAAP
  • WAS
  • CPACC
  • AT
  • JAWS
  • NVDA
  • WAVE
  • WebAIM
  • Deque
  • BOK
  • SC
Answers
  • accessibility
  • user experience
  • perceivable, operable, understandable, robust (can you explain each in simple words, and give an example?)
  • world wide web consortium (standards org)
  • web content accessibility guidelines (practical)
  • web accessibility initiative - accessible rich internet applications (HTML attributes spec to add semantics)
  • authoring tool accessibility guidelines
  • website accessibility conformance evaluation methodology
  • lowest, mid range, highest (usually go with AA)
  • americans with disabilities act (civil, US)
  • government procurement rules (US)
  • recent update to WCAG
  • 21st century communications and video accessibility act (US, communications must be accessible, like TV for example)
  • accessibility for ontarians with disabilities act (civil, like ADA)
  • EN 301 549 is government procurement rules (Europe) (like Section 508)
  • international association of accessibility professionals
  • web accessibility specialist
  • certified professional in accessibility core competencies
  • accessibility tree
  • job access with speech
  • nonvisual desktop access
  • web accessibility evaluation tool
  • web accessibility in mind
  • deque = Deque Systems
  • body of knowledge
  • success criteria

Policy examples and templates for your company

Accessibility statement generator