Accessibility can refer to two distinct, but related concepts. First, it can be an expression of how well people with disabilities are able to utilize (or, access) a product or service. Second, it can refer to the practice of designing and developing products and services to be accessible.
Many users with disabilities will take advantage of some sort of assistive technology (AT). AT augments, adjusts, or even entirely replaces the screen/mouse paradigm of interaction. For example, a blind user may utilize a screen reader, which provides a spoken representation of the screen; a user with impaired motor skills might navigate via keyboard rather than mouse; a user with poor eyesight may zoom their browser or use another screen magnifier.
Note that not all disabilities require the use of AT. A user who is deaf or color-blind or cognitively-impaired may just browse with monitor and mouse, but still encounter content that is difficult or impossible to use. Likewise, most of us will encounter at least minor vision and motor-skill impairment as we age.
Note too that AT is not limited to just desktops or laptops. Touch-based screen readers are available for tablets and smartphones.
In the worst case, poor accessibility can render a site or app totally unusable. Critical content may be unreachable, and critical operations unavailable.
WCAG 2.0 is the most widely-recognized guideline for digital accessibility. While it is not currently broadly required by law, both courts and various government agencies have identified it as a benchmark for accessibility in lawsuits brought under ADA, and it is likely to be the basis for future legislation.
WCAG 2.0 is broken into 3 levels - A, AA, and AAA (AAA being the most stringent). We currently try to comply with AA.
WCAG compliance is a tricky subject. Because WCAG is intended to describe the requirements for accessible digital applications in general, the details of meeting those requirements in a specific technology or design often require additional research and experimentation. Likewise, because WCAG often specifies outcomes instead of implementation details, real-world testing is frequently required. This in turn can be challenging, because UAs and ATs can themselves be buggy, different combinations of UA and AT may produce different results, AT can often be expensive and difficult to learn, etc.
That said, there's a number of things we can do to promote accessibility in our projects:
- Address accessibility early by including it in the visual and technical design process
- Follow best practices and established patterns
- Use automation where viable to test for compliance
- Perform manual testing during development and QA
- Invite disabled users to participate in QA and usability testing
WCAG requires a minimum contrast ratio of 4.5:1 for normal-sized text, and 3:1 for large text (defined as 14pt - roughly 19px - bold weight, or 18 point - roughly 24px - normal weight). See http://webaim.org/resources/contrastchecker/ for a helpful contrast checker. Choosing high-contrast colors helps keep text readable for users with various vision-related disabilities. (1.4.3)
Avoid the use of color alone as a means of conveying information. For example, the error state for a form field may include a change in border or label color, but if that is the sole visual indicator, a color-blind user would be unable to perceive the error. Links should either have a non-color-based visual cue (underlining or bolding, for example) in their normal state, or use a color that provides 3:1 contrast against the surrounding text, and have a non-color-based visual cue in their hover/focus state. (1.4.1)
Information architecture and navigation should use consistent, predictable patterns as much as possible. For example, primary and secondary navigation elements should appear in the same position on every page, and the relative order of their links should be consistent. Note that this doesn't mean the links need to be the same on every page - different pages may show different links or sub menus, or the menu items may vary by some other factor (user authentication, for example).
Other pieces of content or functionality that are used on multiple pages should also be identified and placed consistently within the pages. For example, a component providing site-wide search functionality should use the same label on every page; it should not be labeled 'Search' on one page and 'Find' on another. Likewise, it should not appear in the header on one page and the footer on another. (Note that functionality for searching specific parts of the site can and potentially should have a different labels and placement than the site-wide search.) This predictability is beneficial to all users, but particularly to users of AT, who otherwise would have to spend time learning the structure of each new page before they could use it effectively. (3.2.3, 3.2.4)
All pages should have a descriptive title and descriptive headings should be used to organize content. (2.4.2, 2.4.6)
Pages should typically also be discoverable through at least two ways (navigation, links within pages, search, site map, etc). This gives users with disabilities the option to use whichever mechanism works best for them, and ensures a fallback is available in case they encounter issues. Note that this is not required for pages like a checkout or confirmation screen that represent a step within a process. (2.4.5)
When linking, be sure the purpose of the link is clear either from its text alone, or the surrounding text. Try to avoid link text like "click here", having multiple links to the same destination with different text, or multiple links to different destinations with the same text, as these can all be confusing. (2.4.4)
All meaningful graphical content should have a text alternative that developers can incorporate into the final product. Note that this includes not just bitmap images and photos, but also icons, charts, graphs, some animations, and potentially other graphical content. (1.1.1)
Audio and video files require a variety of alternate content to make them available to users with hearing or vision impairments.
For pre-recorded audio-only content:
- Provide a text transcript or equivalent text content (1.2.1)
For pre-recorded video-only content:
- Provide a text transcript or equivalent text content
- Or, provide an audio track containing a spoken equivalent (1.2.1)
For (pre-recorded or live) video with an audio track, or other combinations of audio and video:
- Provide captions (1.2.2, 1.2.4)
- Provide an audio track containing descriptions of any visual information missing from the default audio track (1.2.3, 1.2.5)
Avoid creating content that relies solely on sensory characteristics that all users might not be able to perceive. For example, instructions to "click the big red button" are not useful to a blind user who can't see the size or color of the buttons on the screen. (1.3.3)
Likewise, when designing interactive functionality, be sure to consider users who cannot operate a mouse. Always include focus states for any clickable element, avoid interfaces that depend entirely on mouse hover, and identify an alternate means of operation for functionality like drag-and-drop (designers and developers may need to collaborate on these sort of interactions). (2.1.1, 2.4.7)
Any animations that start automatically, are presented alongside other content, and run for more than 5 seconds must include a mechanism allowing them to be paused, stopped, or hidden by the user. An exception can be made when the animation itself is essential to the page. For example, an auto-playing slideshow generally would not be essential, and therefore must be pausable, but a loading spinner does not need to be pausable, as its continued playback is essential to understanding that the page or component is still in a loading state. (2.2.2)
Likewise, if content automatically updates, the user should be given an option to stop, pause, hide, or control the frequency of the updates, unless the updates are essential. (2.2.2)
Finally, avoid types of flashes known to cause seizures (2.3.1).
With few exceptions, all form fields should have visible labels. Placeholder text may also be used, but should not be used in lieu of a label. (1.1.1, 3.3.2)
When forms will be validated prior to submission, visual indication of any validation failures should be provided, along with descriptive error messages. (3.3.1, 3.3.3)
Similar forms should use consistent structure and labeling patterns. For example, if two forms on a site ask for the user's Social Security Number, they should use the same label text and input structure. (3.2.4)
TODO identifying required fields
Avoid introducing context changes (navigation to a new page, tab, or window, or a shift in focus within the page) in unexpected places. For example, navigating to a new page in response to a button or link click is expected, but doing so when a link or button is merely focused is not expected and would produce a very confusing experience for many users. Interacting with a form control may produce a context change, but only if the user has been advised of it in advance. For example, a phone number input consisting of three separate fields may auto-advance to the next field when the current field is completed, but instructions advising of this behavior should be included in the page before the form fields. (3.2.1, 3.2.2)
TODO
https://www.w3.org/TR/WCAG20/#time-limits
TODO
Many users with vision-related disabilities will not be able to engage visually with a page. Instead, they rely on AT to communicate the information contained on the page, and expose useful functionality. AT in turn primarily uses the page's HTML to determine what to communicate, how to communicate it, and what functionality to expose. For example, AT may communicate a heading (h1
, h2
, etc) element in a different manner than it would plain text, while also exposing additional heading-specific navigation functionality.
Developers should therefore be familiar with the meaning of different HTML tags and choose them carefully. Most pages have an identifiable structure, and most UI elements an identifable purpose; the HTML should reflect this organization and meaning so that users of AT receive complete and correct information. Ideally, any information that is conveyed visually through the sequence, relative size, color, font face, or other treatment should also be conveyed through the markup.
Additionally, markup should be well-formed and, ideally, validated per W3C (4.1.1).
- Headings should be marked up with
h1
throughh6
tags; don't just style adiv
table
s should be used always and only for tabular data; don't use them for layout purposes, and don't create table-like structures from non-table
elementsol
andul
should be used for ordered and unordered lists, respectivelya
orbutton
should be used for navigation and actions within a pagediv
andspan
should be used for semantically-neutral elements (for example, as styling or scripting containers)em
,strong
, andi
should be used for emphasized, important, or alternate-voice text
Use specific tags and/or the role
attribute to identify landmarks within a document. For example, the main content area should be marked up with a main
tag so that supporting AT can skip directly to it. TODO skip links (2.4.1)
Headings should generally appear in order, where each level of heading represents a subheading within the previous heading's content. (1.3.1)
<h1>Level 1</h2>
<p>Level 1 content</p>
<h2>Level 1.1</h2>
<p>Level 1.1 content</p>
<h3>Level 1.1.1</h2>
<p>Level 1.1.1 content</p>
<h2>Level 1.2</h2>
<p>Level 1.2 content</p>
<h3>Level 1.2.1</h3>
<p>Level 1.2.1 content</p>
<h3>Level 1.2.2</h3>
<p>Level 1.2.2 content</p>
<h4>Level 1.2.2.1</h4>
<p>Level 1.2.2.1 content</p>
This allows AT to navigate an accurate outline of the page's content.
Since AT typically reads elements in the order in which they appear in the DOM, content in the source HTML should typically have a sensible reading order that parallels how it will be presented on screen. So, for example, while it's possible to put a section heading beneath its content in the DOM, but visually position it above that same content via CSS - don't. (1.3.2)
Hidden content
TODO hiding from AT.
Throughout the examples in this document, the visually-hidden
class will be used. This does not necessarily represent a specific class, but is intended to represent the general concept of a style that hides content from the visual presentation while keeping it available to AT. In most cases, content that is styled with display: none
or visibility: hidden
will not be accessible to AT. Often, this is what we want, but sometimes we want to keep content accessible, while still hiding it on the screen. In these cases, a visually-hidden
style is appropriate.
Many developers are already familiar with the alt
attribute of the img
tag; this attribute should be present on every img
, though its content may be an empty string when the image is purely decorative. When a screen reader encounters an img
, it will read the content of the alt
attribute (when the alt
attribute is not present, the file name may be read instead, which is why an empty string should be used for decorative images).
<!-- this is a decorative image -->
<img alt="" src="decorative-image.jpg" />
<!-- this is a meaningful image -->
<img alt="information about or equivalent to the image" src="meaningful-image.jpg" />
Note that CSS background images do not have alternate text, nor are they typically accessible to AT. This makes them ideal for decorative images. However, be careful not to abuse background images by using them for meaningful images without a text alternative.
Icon fonts are a common way to include simple graphics, but they do not use img
tags. Rather, they typically use CSS to insert their content via pseudo elements. Because they are not img
s, developers often neglect text alternatives. Additionally, because some screen readers will read pseudo elements, use of icon fonts can cause unpronounceable characters to be spoken. To address these issues, when using icon fonts, developers should place the icon in its own element with the aria-hidden
attribute set to true, and add a visually-hidden text alternative in a sibling element.
<span>
<span class="my-icon" aria-hidden="true"></span>
<span class="visually-hidden">Alt text</span>
<span>
Note that a text alternative may not be necessary if adjacent text suitably describes the icon:
<a href="http://facebook.com">
<span class="facebook-icon" aria-hidden="true"></span>
Facebook
</a>
As much as possible, avoid images of text, and use web fonts instead. (1.4.5)
TODO
Graphical content may also be included via HTML canvas elements, inline SVGs, and CSS shapes (basic graphics created by clever composition of CSS rules - for example, arrows or hamburger menus). In all cases, developers should ask themselves whether the visual content adds meaning that a non-sighted user would benefit from. For example, a hamburger menu constructed using pure CSS may be recognizable to a sighted user, but a user of a screen reader would not be able to identify it without additional instruction. (1.1.1)
Developers should take a couple steps to provide support for keyboard-only users:
- Clickable elements also need to be focusable, so they can be reached with a keyboard
- Clickable elements should respond to keyboard events as well as mouse events, so they can be invoked via keyboard
- Any other mouse- or touch-based interaction (drag and drop, for example) should have a keyboard alternative
- Focus states should be implemented as designed
- Additional key commands should be recognized as required for specific UI patterns
In many cases, the first two requirements can be addressed via semantic markup. Does clicking the element in question trigger some sort of navigation? Use an a
tag. Does it invoke an action on the same page? Use a button
tag. Is the element a custom form control? Try using styled built-in form controls (see below for more info). Because these are all standard HTML elements, browsers will provide robust built-in keyboard support. (2.1.1, 4.1.2)
Users with impaired eyesight may utilize screen magnifiers or browser zoom to enlarge content. These days, most browsers support this without issue, but developers should still spot-check their work at 200% browser zoom. (1.4.4)
HTML forms can typically be submitted both explicitly - by clicking the default submit button - or implicitly - by hitting 'enter' within a form field. Most (all?) browsers support both mechanisms, and many users expect both to be available.
The simplest way to accommodate this expectation is to ensure form fields are always contained within a form
element, and use the form
's submit
event to trigger any client-side processing (validation, AJAX submissions, etc). This event will fire for both implicit and explicit submission. (3.2.2)
When a submit button is present in the design, it should be coded using a <input type="submit" value="Label" />
or <button type="submit">Label</button>
; non submit-type buttons, styled a
tags with attached click handlers, etc, should not be used.
Bonus: on mobile Safari (and possibly other mobile browsers), the on-screen keyboard's 'return' button will change its text to 'Go' when on a field inside a form
element (provided the action
attribute is specified).
All form fields should have a programatically-associated label. (2.4.6, 3.3.2)
For visible labels, this means using a label
element, either containing the input in question, or associated with it through the label
's for
attribute.
<label for="field-1">Field 1</label>
<input type="text" name="field-1" id="field-1" />
<label>
Field 2
<input type="text" name="field-2" />
</label>
Using label
in this manner allows AT identify the input in question using the specified label text. For example, when a screen-reader user focuses on the first field in the preceding example, the text 'Field 1' will typically be read.
Most browsers also have built-in behavior to translate clicks on a label
into some action on their associated input. Text inputs and selects are typically focused; radio buttons and checkboxes are typically toggled. This functionality is particularly useful for radios and checkboxes, since the control's click target would otherwise be very small and difficult to reach for many users.
Hidden labels
Form fields will sometimes be designed without labels, but this doesn't mean labels are optional; rather, a label needs to be provided in a manner that is both accessible and hidden from view.
This can be accomplished using visually-hidden label
s in the manner described above, or by using the aria-label
or aria-labelledby
attribute.
<label for="field-3" class="visually-hidden">Field 3</label>
<input type="text" name="field-3" id="field-3" />
<label>
<span class="visually-hidden">Field 4</span>
<input type="text" name="field-4" />
</label>
<input type="text" name="field-5" aria-label="Field 5" />
<span id="field-6-label" style="display: none">Field 6</span>
<input type="text" name="field-6" aria-labelledby="field-6-label" />
Note that, typically, elements which are styled with display: none
or visibility: hidden
will not be accessible. However, their content will be included in another element's accessible name/description when referenced by its aria-labelledby
or aria-describedby
attribute (see https://www.paciellogroup.com/blog/2015/05/short-note-on-aria-labelledby-and-aria-describedby/).
Note also that the HTML5 placeholder
attribute is not a label.
Required fields should be identified using the HTML5 required
attribute. This allows AT to identify to the user that the field is required. (3.3.3)
<label for="field-7">Field 7</label>
<input type="text" name="field-7" id="field-7" required="required" />
Note that default browser validation/styling may need to be disabled or overridden when using this attribute.
Related fields should be grouped inside a fieldset
element, with a legend
as its first child. This is particularly important for checkbox and radio button lists, which typically include both a prompt (the legend
) for the group as a whole and labels for each individual item. (3.3.2)
<fieldset>
<legend>Group</legend>
<input type="radio" name="field-8" id="field-8-option-1" value="option-1" /> <label for="field-8-option-1">Option 1</label>
<input type="radio" name="field-8" id="field-8-option-2" value="option-2" /> <label for="field-8-option-2">Option 2</label>
<input type="radio" name="field-8" id="field-8-option-3" value="option-3" /> <label for="field-8-option-3">Option 3</label>
</fieldset>
Note that some screen readers are a bit particular about how and when they will read legend
s (see http://webaim.org/discussion/mail_thread?thread=6714 for a good discussion of the issues). This section may be updated.
Instructional content may be associated with a form field through its aria-describedby
attribute. This content then becomes part of the field's accessible description, which AT will make available to the user. (3.3.2)
<label for="field-9">Field 9</label>
<input type="text" name="field-9" id="field-9" required="required" aria-describedby="field-9-description" pattern="^(\d{3})[ -.]?(\d{2})[ -.]?(\d{4})$" />
<div id="field-9-description">Please enter a 9-digit SSN with or without dashes or spaces</div>
An element can have multiple descriptions - just add additional IDs to its aria-describedby
. Note that in some UA/ATs, it is necessary to specify a tabindex
(typically -1
) on the description elements if multiple descriptions are present.
HTML5 introduced a plethora of new input types for email, dates, telephone numbers, urls, etc. While UA/AT support can be a bit spotty, that's no reason not to take advantage of the additional semantics and behaviors of these new input types.
Invalid form fields should have the aria-invalid
attribute set to true
after the field has been interacted with or the form has been submitted. A description of the error or how to fix it (if known) should either be contained within the field's label, or be associated with the input via its aria-describedby
attribute. (3.3.1)
If submission fails on either client- or server-side validation, a list of errors should be presented and focused, or focus should be shifted to the first invalid field in the form. In both cases, AT will respond to the change in focus by announcing the newly-focused element, thereby informing the user of the error state. And in the latter case, by focusing the first form field, we save the user the trouble of having to find the errored field within the form. (3.3.1, 3.3.3)
<!-- before submission -->
<label for="field-10">Field 10</label>
<input type="text" name="field-10" id="field-10" required="required" />
<!-- after failed submission -->
<label for="field-10">Field 10</label>
<input type="text" name="field-10" id="field-10" required="required" aria-invalid="true" aria-describedby="field-10-description" />
<div id="field-10-description">Error: Field 10 is required; please complete</div>
TODO
TODO
Developers have a couple options for creating custom form controls. As much as possible, it's recommended to utilize standard HTML5 controls and apply creative styling. The standard checkbox, radio, text, select, etc controls are well-supported by AT, offer a well-understood user experience for disabled users, and often have extensive built-in functionality that would be difficult to replicate.
That said, if the built-in HTML5 controls are not sufficient, true custom controls may be used, provided they adhere to the ARIA design patterns (4.1.2).
When navigating with a keyboard, focus determines which element will receive keyboard events (and, consequently, which element the user can interact with). For example, when a link has focus, a keyboard user may follow that link by clicking enter. Focus will be set automatically by the browser as a user tabs through elements, but it may also be set programmatically.
Typically, developers should only manipulate focus in response to a user action that requires a change in focus. For example, clicking a button to open a dialog should result in a change in focus, but focusing or typing into a text field generally should not. In both cases, the goal is the same - to keep the experience consistent and predictable. (3.2.1, 3.2.2)
- When removing or hiding an element that has focus (this includes removing an element whose descendant has focus). If the focused element is removed or hidden, the browser will typically revert focus back to the document or browser window, causing the user to lose their place on the page. If the element in question was added in response to a user action (for example, a dialog), focus should be returned to the element that initiated the action (assuming it is still in the DOM).
- When adding or showing an element that is intended to occlude the rest of the UI. For example, a modal dialog or loading overlay. In this scenario, in addition to shifting focus to the new element or a descendent, event handlers should intercept focus/tab key events to prevent any other elements from receiving focus.
- When form submission errors, focus should be moved either to a list of the errors, or the first errored field in the form.
- When implementing other specific UI patterns that require it.
- When transitioning between screens in a single page application. This can make for a more fluid experience.
- When expanding a collapsible content region, focus should be shifted to the region.
Be sure only to trap focus when absolutely necessary, and when focus is trapped, be sure to provide instructions for how to release it. (2.1.2)
Much like the overall order of content within the DOM, tab/focus order should generally follow the visual presentation of the page, so that users can tab through in a natural order. In most cases, this can be accomplished simply by ordering elements properly within the source HTML; explicitly setting a >0 tabindex should be avoided. (2.4.3)
TODO
Ideally, QA will not need to do a formal validation of the WCAG design requirements. Rather, those requirements should be addressed in the design phase, and QA therefore can be responsible for general design validation.
Functional testing should be performed on all of the following:
- At least 1 popular screen reader/browser. See WebAIM's latest survey for some suggestions.
- With keyboard only.
- At 200% browser zoom.
If available, users with disabilities should be brought in periodically for testing.
- https://www.w3.org/WAI/intro/wcag
- https://www.w3.org/WAI/WCAG20/quickref/
- https://www.w3.org/TR/wai-aria-practices/
- https://w3c.github.io/aria-in-html/
- http://webaim.org/
- http://oaa-accessibility.org/
- http://a11yproject.com/
- https://www.marcozehe.de/
- http://www.karlgroves.com/
- http://www.deque.com/blog/
- https://www.paciellogroup.com/blog/
- http://www.weba11y.com/
- https://a11ywins.tumblr.com/
- https://www.wuhcag.com/wcag-checklist/
- http://www.nvaccess.org/
- http://www.ssbbartgroup.com/blog/
- http://alastairc.ac