Skip to content

Styleguide: Accessibility

alisan617 edited this page Aug 10, 2016 · 57 revisions

General

This document is supplemental to our main styleguides:


Recipes and Snippets


Other accessibility considerations


HTML5 Doctype

HTML5 provides a variety of new semantic elements and attributes, many of which trickle down to the Accessibility API. That means by using HTML5, we get more accessibility 'for free' and setting the right DOCTYPE is a great place to get started.

<!DOCTYPE html>

Landmarks and Roles

Landmarks and roles provide richer semantics to how a page is structured. This allows users some of assistive technology to quickly navigate to designated sections. These can also act as supplementary "bypass blocks", allowing users to bypass repetitive elements of the page such as the header and navigation and get right to the content.

Header and Banner

The header element specifies a header for a document or section. It typically contains a heading (Level 1 to 6) for the document or section, but can also contain a table of contents, navigation, or a search field.

<header>
    <!-- Stuff here -->
    ...
</header>

The ARIA role="banner" is used to indicate mostly site-oriented content rather than page-specific content.

<header role="banner" aria-label="Purpose of header">
    <!-- Page header -->
    ...
</header>
  • The header element should be used as a container for introductory content
  • You can have several header elements in one document
  • You may only use a single role="banner" and it must be used on a header element.
  • Always use an aria-label that describes (concisely) the purpose of the header on the header that contains the role="banner". For example: "main" or "page".

Navigation

The nav element represents a section of a page that links to other pages or to parts within the page: a section with navigation links. The nav element has an implicit ARIA role="navigation", which is used to indicate a collection of links to navigate the document or related documents.

<nav aria-label="Site">
    <!-- Screen readers would announce this as "Site navigation" -->
    <ul>
        <!-- List items with links -->
        ...
    </ul>
</nav>

Typical forms of navigation include site navigation, section navigation, page navigation, utility navigation, and footer navigation. The nav element usually wraps an unordered list, but doesn't have to.

  • You may use any number of nav elements.
  • Be sure to include an aria-label that describes the navigation as screen readers will include this information when the role is announced; don't include the word "navigation".

Main

The main element is used to indicate the content that relates directly to the central topic of the document.

<main aria-label="Content">
    ...
</main>
  • There should only be one main element
  • Be sure to include aria-label="Content" so screen readers announce this as the "main content".

Search

The ARIA role="search" is used to define a region where search functionality is located.

<div role="search" aria-label="Course">
    ...
</div>
  • Be sure to include an aria-label that describes the scope of the search (i.e., site, course, notes, etc.)

Complementary

The ARIA role="complementary" is used to indicate content that is complementary to the main content, yet has meaning when separated from the main content.

<div role="complementary" aria-label="References">
    ...
</div>
  • Remember to add the aria-label that describes the scope of this complementary content, as it makes it easier for screen reader users to navigate directly to the region or browse a list of available regions on the page.

Footer, contentinfo

The ARIA role="contentinfo" indicates a region that contains information about the parent document. It often contains information like copyright and privacy statements and usually attached to the footer. This role is automatically implied when the footer element is used.

<footer>
    ...
</footer>

<div role="contentinfo" aria-label="Website footer">
    <!-- Copyright, privacy, terms, etc. -->
    ...
</div>
  • Much like header, you may use multiple footer elements per page
  • Be sure to include a relevant and descriptive aria-label
  • You may use role="contentinfo" only once and it should be on the page or body footer. Don't use it on any other footer elements.

Native HTML5 elements

It's important to understand the native roles of elements and use them accordingly.

Form fields

Some of the more common input types that are useful to know are text, email, tel, and date. While these new types offer improved functionality for desktops, they really shine on mobile.

When adding form fields:

  • Always use a label that identifies the field (i.e., <label for="name">Name:</label><input id="name" />)
  • Establish a explicit connect between a label and an input by pointing the for to the id respectively
    • Even better, wrap the label around the input for better semantics. Note, if you do this, you don't necessarily need to use the id or a for as it becomes implied.
  • The name attribute isn't required, but it is helpful for normal form submissions that don't leverage JavaScript. We recommend using it for progressive enhancement.
  • Using aria-describedby and referencing an id will aid with help text that isn't contained within the label element. This comes in handy for help text or additional information about the data to be entered since screen reader users are unlikely to be exposed to this important information while in "forms processing mode".
    • An excellent example of this usage would be using aria-describedby to reference nearby help text with an id that matches the aria-describedby.
HTML5 Form Fields
<input type="text">
  • Desktop: standard input field
  • Mobile: normal keyboard
<input type="email">
  • Desktop: standard input field
  • Mobile: keyboard tailored for easy email typing, including the @ symbol
<input type="tel">
  • Desktop: standard input field
  • Mobile: number pad keyboard suited for entering phone numbers
<input type="date">
  • Desktop: most newer browsers display a built-in datepicker
  • Mobile: usually a date spinner is presented for easy date picking

Buttons and Links

A good rule of thumb is: Buttons do something; links go somewhere.

Do this:

<button>I'll do something</button>

Not this (the role here isn't necessary):

<button role="button">I'll do something</button>

Or this:

<a href="#" role="button" class="button">Link that looks like a button</a>
  • button's are not required to appear within a form. Using the form element only aids with graceful degradation in instances where JavaScript isn't available.
  • It is recommended that you supply a type. The available types are:
    • submit: The button submits the form data to the server. This is the default if the attribute is not specified, if the attribute is dynamically changed to an empty or invalid value, or if no role is specified.
    • reset: The button resets all the controls to their initial values.
    • button: The button has no default behavior. It can have client-side scripts associated with the element's events, which are triggered when the events occur.

Sections and Articles

The section element defines a section in a document. It should contain a heading. It should not be used as a stylistic wrapper as it has meaning.

<section>
    <h2>This is a list of articles</h2>
    <header>
        <nav role="navigation" aria-label="Article">
            ...
        </nav>
    </header>
    <article>
        <h3>Article title</h3>
    </article>
    ...
    <footer>
        ...
    </footer>
</section>

Taborder and Focus

Tab order is the order in which focus is moved throughout the document when navigating using the Tab key. Tab order follows the DOM and moves from the top of the DOM to the bottom. It is important ensure that the default tab order of your page presents elements in a logical order, even when manipulating the DOM with JavaScript.

If manipulating the default order is necessary to provide a logical tab order (like when displaying a modal dialog box), or when building custom Javascript widgets, there are two ways to do it:

#####tabindex="0" Allows an otherwise unfocusable element to be focused in the normal tab flow

#####tabindex="-1" Allows programmatic focus to be sent to an element through scripting, and is only required when attempting to make things that are not natively focusable, focusable.

When opening a modal, send focus to it

HTML:

<div class="modal" tabindex="-1" aria-hidden="true">
    ...
</div>

Script:

var initiator = document.activeElement;
$('.modal').show().focus().attr('aria-hidden', 'false');

When closing a modal, return focus to the element that triggered it (initiator)

By sending focus back to the initiating control, we help maintain a natural, logical page flow.

HTML:

<button class="close">Close</button>

Script:

$('.modal').on('click', '.close', function() {
    $('.modal').hide().attr('aria-hidden', 'true');
    initiator.focus();
});

Note: When a modal or dialog box is opened, subsequent Tab presses should trap focus within the modal. Additionally, pressing the ESC key should perform the same action as pressing the close button.


Using Icon Fonts

When using icon fonts, it's important to remember to:

  • use off-screen text if the icon is displayed by itself
  • hide the icon from audible output with aria-hidden="true"
  • never use an icon without equivalent text

Icons with visible labels

<div class="icon-display">
    <span class="icon fa fa-exclamation-circle" aria-hidden="true"></span>
    <span class="text">Error</span>
</div>

Icons by themselves, without a visible label

<div class="icon-display">
    <span class="icon fa fa-exclamation-circle" aria-hidden="true"></span>
    <span class="sr-only">Error</span>
</div>

Using aria-hidden

Make sure to include aria-hidden="true" with all icons. Otherwise screen readers may try to announce the icon which could confuse users. Make sure there is equivalent text that explains the icon if it's being used by itself. This text may use the .sr-only class to hide it visually if only the icon is desired.


Form Field Helper Text

Sometimes it's necessary to include helper text for a form field that's displayed below the field. Since screen readers read through the DOM linearly we need to ensure the helper text is announced.

Example:

<form>
    <label for="email-address">Email address:</label>
    <input type="email" name="email-address" id="email-address" aria-describedby="helper-email-address">
    <span id="helper-email-address">Must be a valid email address. Example: user@domain.com</span>
</form>

Figures

When groups of images, charts, or graphs are to be used, or when the alt attribute text is different from the visual caption, use the figure element and include all of the media within it. The alt attribute values of the included media should still be defined. You may use figcaption to summarize the group in its entirety.

A single image with a caption:

<figure>
    <img src="path/to/image.png" alt="Puppies playing in a field">
    <figcaption>Samwise Gamgee enjoys watching his puppies play in the green grass</figcaption>
</figure>

Multiple images, or charts, with a collective caption:

<figure>
    <img src="chart-01-apples.png" alt="46% apples" aria-describedby="chart-caption">
    <img src="chart-01-oranges.png" alt="54% oranges" aria-describedby="chart-caption">
    <figcaption id="chart-caption">Ratios and percentages comparing apples to oranges</figcaption>
</figure>

Note the use of aria-described here, programmatically linking the image to the caption


Targeting content for specific audiences

There are several mechanisms that can be used for hiding content. It's important that a technique be implemented that results in the desired outcome and accessibility.

Content just for screen reader users

A fairly modern technique of using CSS to hide or clip content that does not fit into a 1 pixel visible area will essentially hide the content visibly, but still allow it to be read by modern screen readers.

position: absolute;
clip: rect(1px, 1px, 1px, 1px);

Useful when:

  • Wanting to include additional/supporting/contextual information for screen readers, but hide it visually

Note: edX provides an .sr class that can be applied to any element or content that will automatically perform the above. We recommend using it.

Example:

<span class="icon fa fa-home" aria-hidden="true"></span>
<span class="sr">Dashboard for:</span> John Smith

Hiding content aurally

Sometimes we need to hide content from screen readers only, but have it shown to sighted users. This is primarily the case for icon fonts or other decorative stuff. Rather than using CSS to control this, we use HTML. You'd place the following in your markup:

aria-hidden="true"

An example of this would be:

<span class="icon-font icon-angle" aria-hidden="true"></span>

This would display the icon visually, but not announce it to screen readers. Since icon fonts often precede actual text, the text would still be announced and the action would still be clear. Hiding the icon only helps add clarity.

Useful when:

  • Wanting to hide certain decorative elements such as icons from assistive technology, but show them visually

Hiding content from everyone

These styles will hide text from all users. The text is removed from the visual flow of the page and is ignored by screen readers. Do not use this CSS if you want the content to be read by a screen reader. But DO use it for content you don't want read by screen readers or perceived visually. If you do include this mechanism, make sure you move focus to the element when it is displayed!

display: none

Useful when:

  • Programmatically hiding or showing content that is in the DOM but not relevant to the current task
  • Loading a modal and its content
  • Loading tabbed content

Using images: DOM or CSS?

When it comes to using and including images in your document, where's the best place to put them? The easy answer is: If the image provides context or meaning, it should be in the DOM. A good example of this is the edX unit navigation which lets students navigate between sections within a course. The icons provide context as to which type of content to expect (video, assignment, problem, etc.) and should be included in the DOM (and therefore announced to screen readers).

If the images are purely decorative, they can be shown using CSS. If a decorative image is being used in the markup, be sure and use an empty alt attribute (alt="") so it's not announced.


Embrace the focus ring

The focus ring (the blue glow or dotted line that appears on buttons, links, or anything that has focus) is extremely important to people who rely on the keyboard to navigate. It indicates where focus is! Many designers disable or downplay the focus indicator, but this severely limits the ability to use a keyboard effectively and hurts the overall user experience.

We recommend leaving the styles alone and letting the browsers determine how they are displayed. If you feel strongly against the native browser styling of the outline and a focused state, you may re-style the focus (keeping in mind existing application focus style standards and options), but under no circumstances should you remove it.

// Example: nope
:focus {
    outline: none;
}

// Example: Yep (but with consistent application outlines in mind)
:focus {
    outline: 2px solid yellow;
}

Using What-Input to determine focus

We are utilizing the What Input JavaScript plugin which monitors the input device (keyboard, mouse, finger) used for interactions and allows us to customize the experience accordingly. For example, if a user is Tabbing through the interface with a keyboard we want focus indicators to appear on everything. But if a user is interacting with a mouse, we may want to hide the focus indicators. This plugin allows us to design the perfect experience for every user.


Don't over-engineer

When building your site, take care not to overdo the engineering. Going overboard with ARIA can actually make your application less accessible. Understand the native roles of the elements you're using. Consider the following:

<button role="button">Button</button>

The role above isn't necessary because a button already has that role.

Similarly...

<a role="button">Link-tton</a>

Using role above changes the native role of the link. In this case, just use a button.