Skip to content

Styleguide: Accessibility

Mark Sadecki edited this page Mar 12, 2015 · 57 revisions

General

This document is meant to be referenced alongside the following styleguides:


Recipes and Snippets


Other accessibility considerations


HTML5 Doctype

<!DOCTYPE html>

(BT: What does the doctype do for us? Should we list any brief reason why this is needed (I'm assuming for easier rendering and support of native elements.))

(MS: I agree with Brian here. We need a little context. Perhaps we can say something like "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." )


Landmarks and Roles

Landmarks and roles provide meaningful, semantic keys to specific sections of the page. This allows users of assistive technology to quickly jump to designated sections. These can also act as supplementary "skip navigation" mechanisms.

(MS: Not sure we should use the word "keys" here as it can be confused with keys on a keyboard. How about "provide richer semantics to how a page is structured." also "users of some assistive technology..." consider "quickly navigate to..." I'm a little uncomfortable with referencing "skip navigation" since the standard is "skip to main content". We may want to consider the technical description for this, which is "Bypass Blocks" (WCAG 2.4.1), and link to the actual WCAG document )

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 aria-label="Purpose of header">
    <!-- Stuff here -->
    ...
</header>

(MS: I actually do not recommend adding an aria-label to simple header elements, especially if the header includes a child heading element. Screen readers do not provide direct navigation or browsing of header elements, except for the one with role=banner, which is why I DO recommend aria-label on that one. To be honest, there is no accessibility benefit to using the simple header nested inside an article as above, only the banner one below.)

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. For example: "main" or "page". (MS: We should probably be explicit on that last bullet point that this is only on the header with role=banner)

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 ARIA role="navigation" is used to indicate a collection of links to navigate the document or related documents.

(MS: We are not using a role="navigation" in our example, so its confusing to reference it above. It's fair to point out that the nav element has an implicit aria role of navigation. )

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

(MS: add last bullet point to code example?)


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 aria-label="Article meta">
    ...
</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 footer

(MS: Footer follows the same pattern as header above. Only the footer that is a child of the body element or has a role=contentinfo has any accessibility benefit. I do not recommend adding an aria-label to other footer elements on the page, so we should make that clear in bullet 2.)


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
  • The name attribute isn't required, but it is helpful for normal form submissions that don't leverage JavaScript
  • 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.

(MS: Bullet #3 isn't accessibility related and can be removed IMHO. I think we should be more explicit about the why in Bullet #4 "...data to be entered since screen reader users are unlikely to be exposed to this important information while in "forms processing mode".)

<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, or if the attribute is dynamically changed to an empty or invalid value.
    • 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.

(MS: type=submit is implied on a button element with no explicit role)

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 tab order must be set, there are two ways to do it:

(MS: consider "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: )

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

#####taborder="-1" allows programmatic focus to be sent to an element through scripting

(MS: It might be fair to note that this 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

<a href="#"><i class="icon fa-question-mark" aria-hidden="true"></i> Get help</a>

Icons by themselves, without a visible label

<a href="#"><i class="icon fa-close" aria-hidden="true"></i> <span class="sr">Close</span></a>

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.


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: [email protected]</span>
</form>

Figures

For semantics, wrap your images in figures. You can have more than one img within a figure. Using a figcaption is optional but if used, should add clarity to the figure whether it's a single image or a collection of images.

(MS: This is a useful technique, but the way it is included here seems to imply that this should always be used. The vast majority of the time a simple img with alt is all that is required.)

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


Hiding content

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.

(MS: I'm not sure this is the right title for this section. Some developers don't even know why they would want to hide content. And since this is specifically for accessibility, perhaps we can put it in that context. Suggestion: "Targeting content for specific audiences". I also think you should put the primary technique, which is Hiding content visually, first in the order. And Hiding content visually and aurally last, if at all since its not explicitly accessibility related.)

Hiding content visually and aurally

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.

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

(MS: Suggest title "Hiding content from everyone". If you do include it, add accessibility guidance, like "Make sure you move focus to it when it is displayed" )

Hiding content visually

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

(MS: Suggest title: "Content just for screen reader users")

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.

_(MS: A code sample here would be good. Perhaps the one used on our user menu for dashboard is good:

<!-- The icon conveys Home or Dashboard visually but is not accessible to a screen reader user -->
  <i class="icon fa fa-home" aria-hidden="true"></i>
<!-- The user name by itself does not contain enough context to describe the destination of the link -->
<!-- Include additional context for the link that is not displayed visually using class "sr" -->
  <span class="sr">Dashboard for:</span>
  John Smith
<!-- A screen reader user hears "Dashboard for: John Smith" while a sighted user sees a home icon and their user name -->

)_

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:

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

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

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 are you to remove it.

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

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

// Example: Yep (just use the browser default)
:focus {
}

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.

Clone this wiki locally