- zoom-friendly layouts
- keyboard navigation
- screen reader usage
- impairments, which may be permanent or temporary
- vision impairments
- hearing impairments
- motor acuity or dexterity impairments
- cognitive impairments (e.g. dyslexia)
Four core principles (POUR):
(see WCAG checklist)
Focus determines where keyboard events go in the page; i.e. focusing on elements, e.g. by clicking, tab key, etc.
A lot of web accessibility deals with managing focus.
Tab moves focus forward;
Shift+Tab moves focus backwards; arrow keys move focus w/in a component.
Tab order determines the order focus moves through on the page.
HTML inputs & interactive elements are implicitly focusable, i.e. are automatically in the tab order (based on position in the DOM; CSS can change the visual order w/o changing the DOM order) and have built-in keyboard event handling.
tabindex attribute can be used to manually insert something into the tab order.
tabindex="-1" is not in the "natural" tab order but can be manually focused via JS's
tabindex="0" places it in the natural tab order
tabindex values > 0 can mess up the tab order, so avoid this!
As a general rule,
tabindex should only be added to interactive elements.
One exception: when content changes due to user interaction, e.g. changing tabs in a single page app. In these cases you'd use
tabindex="-1" and call
focus() on it after the interaction.
Focus on a page often starts with header & other nav elements, not the main content. This can mean a lot of unnecessary tabbing for users. One common practice is to add a hidden "skip link" as the first interactive element that can be used to skip focus to the main content.
Skip to main content
When making custom interactive components, refer to the ARIA Design Patterns doc, which lists keyboard shortcuts for HTML widgets, which you should implement.
Roving focus: when focus in an element rotates, e.g. in a set of radio buttons.
Dealing w/ off-screen elements (e.g. off-screen menus):
document.activeElement tells you the currently-focused element
- Chrome Accessibility Dev Tools extension can also help with this
display: none or
visibility: hidden will resolve this
Keyboard trap: when a user cannot tab out of the focused element. Normally, this is undesirable, but it is desirable for some cases, eg. modals where you don't want focus to leave the modal. Currently no easy way to do this (some ideas have been proposed); you have to implement it yourself.
Note: when you close a modal, it should restore focus to the previously-focused element (if appropriate).
Includes: screen readers, text-to-speech, voice control, Braille display, etc...
Screen Readers read out for an element:
name, if present
value, if present
state, if present (e.g. "selected")
"Implicit semantic meaning" - when using standard HTML elements, a lot of the above semantics come by default.
Provide text alternative for any non-text content, e.g.
alt text. Note that
alt is different than
alt text is shown if the image is broken and should be a description of the image, not just a title.
Screen readers follow DOM order, not visual order, so bear that in mind, e.g. w/ headings.
alttext for the image.
In the first two cases, you should use a
The purpose of a link should be discernible from the link text alone, without assuming surrounding context.
Landmarks for quick navigation:
mainelement (should only be one)
articleelement (rule of thumb: use if the content makes sense in different contexts)
asideelement (e.g sidebars)
Web Accessibility Initiative - Accessible Rich Internet Applications; for accessibility that is currently beyond the scope of native HTML.
E.g. if we had to create a custom checkbox, a screen reader wouldn't know our checkbox is meant to be equivalent to the HTML checkbox. We can tell it this with
aria-checked="true". These do not modify element behavior or implement keyboard shortcuts, etc.
ARIA also lets us create new widgets that aren't just recreations of existing HTML elements.
ARIA has an
alert role which a screen reader may read immediately.
ARIA labels can be used to add help description text to any element:
aria-labelledby, to identify an element A as the label for element B. This can take multiple elements, but does not provide the clicking behavior HTML labels provide, e.g. for checkboxes.
aria-describedby, e.g. password requirements hint
There are some limitations on what ARIA roles can be used w/ what HTML elements. E.g. an
<input type="text"> can't have
role="heading". Generally, ARIA can't conflict w/ implicit semantics.
aria-labelledby is an example of a "relationship attribute", which defines a semantic relationship b/w two elements.
aria-owns is another which says that an element that's separate in the DOM should be treated as another element's child, e.g:
Elements w/ the
visibility:hidden CSS or the
hidden HTML attribute will be hidden from assistive technologies. Hidden elements related w/ e.g.
aria-describedby will still be read.
aria-live indicates an element that will have its content updated and should be communicated to the user. It can be
polite (will wait until next free moment), or
assertive (will interrupt).
aria-live elements should be part of the initial page load.
aria-atomic: if true, the region is treated as a whole on change. Otherwise, only the changed part is read.
aria-relevant: indicates what types of changes are read, e.g.
additions text (default)
aria-busy: temporarily ignore changes to this element
32dpmargin around touch target