-
Notifications
You must be signed in to change notification settings - Fork 39
Styleguide: Accessibility
This document is supplemental to our main styleguides:
- General Front End Styleguide
- Accessibility Styleguide
- HTML Styleguide
- Forms Styleguide
- Sass & CSS Styleguide
- JavaScript Styleguide
- HTML5 Doctype
- Landmarks and Roles
- Form fields and inputs
- Tab Order and Focus
- Using Icon Fonts
- Form field helper text
- Figures
- Hiding content
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 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.
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 aheader
element. - Always use an
aria-label
that describes (concisely) the purpose of theheader
on theheader
that contains therole="banner"
. For example: "main" or "page".
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".
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".
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.)
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.
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 multiplefooter
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 otherfooter
elements.
It's important to understand the native roles of elements and use them accordingly.
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 aninput
by pointing thefor
to theid
respectively- Even better, wrap the
label
around theinput
for better semantics. Note, if you do this, you don't necessarily need to use theid
or afor
as it becomes implied.
- Even better, wrap the
- 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 anid
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 anid
that matches thearia-describedby
.
- An excellent example of this usage would be using
<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
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 aform
. Using theform
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 norole
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.
-
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>
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.
HTML:
<div class="modal" tabindex="-1" aria-hidden="true">
...
</div>
Script:
var initiator = document.activeElement;
$('.modal').show().focus().attr('aria-hidden', 'false');
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.
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
<div class="icon-display">
<span class="icon fa fa-exclamation-circle" aria-hidden="true"></span>
<span class="text">Error</span>
</div>
<div class="icon-display">
<span class="icon fa fa-exclamation-circle" aria-hidden="true"></span>
<span class="sr-only">Error</span>
</div>
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.
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>
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
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.
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
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
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
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.
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;
}
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.
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
.