Impairments Basics
Impairments can be visual, auditory, mobile, cognitive, or speech based. They can also be situational, temporary, or permanent. Not being able to see your screen well outside during a sunny day is an example of a situational visual impairment, having a concussion is an example of a temporary cognitive impairment, and having an absent limb could be an example of a permanent mobile impairment.
When we build web content, we need to keep impairments in mind. Building with impairments in mind will help all of our users.
When thinking about how to best help our users, we need to remember:
Some users navigate using a keyboard only, having all interactive content accessible by keyboard is essential (note, all interactive content. Adding things like headings to the tab order can be confusing and lead to trouble with finding content that is needed…more on this later)
Anything that is sound based should have a visual as well
Don’t over design. Optionally, have a minimal design option for users with cognitive impairments to reduce distraction and cognitive load
WCAG Basics
WCAG provides a benchmark for accessible content. It is build around four principles of what we content should be for users.
Web content should be:
Perceivable - making sure users can receive content regardless of impairments
Operable - making sure users can operate ui components and navigate content
Understandable - making sure all user understand the interface and it is consistent enough to avoid confusion
Robust - making sure it is robust enough to be consumed by a wide variety of users and it works with assistive technology.
This is commonly referred to as POUR.
Following WCAG guidelines will get your content most of the way when it comes to accessibility. Just remember, we’re building content for USERS, not to fill out a checklist. Verify the tab order (more on this soon) and that your content is working with a screen reader (more on this soon) to make sure your page is truly accessible. User experience is much more important than checking off a box.
Focus/Tab Order
Users should be able to access all interactive elements from their keyboard, specifically from clicking tab. This is the first thing to check on a page you’re assessing for accessibility.
The tab order should be logical, from top right to bottom left. If CSS has moved an element to a different part of the page and that’s affecting the tab order, the item needs to be moved in the HTML. Tab order is based on the DOM.
Native HTML Elements have focus build into them (you will automatically be able to tab to input and button elements, for example), but rarely (it should be pretty rare) you will need to create a custom HTML element.
You can add/alter focus behavior with the attribute tabindex:
-
tabindex=”-1”
- Element will not be in the natural tab order
- Element can be programmatically focused with focus() method
- This is very useful for content that is offscreen and appears on screen after a user event (such as a dashboard being offscreen until a user clicks a hamburger menu)
-
tabindex=”0”
- Element will be in the natural tab order
- Element can be programmatically focused with focus() method
-
tabindex=”3” (or anything greater than 0)
- This is an ANTI-PATTERN, do not do this. It can jumble the tab order and is very confusing to screen readers
- Element will be in the natural tab order
- Element will jump to the front of the tab order
- If there are multiple, the order will start at the smallest above zero and work it’s way up
When to implement focus behavior
Focus behavior should only be added to input controls (for example, buttons and other interactive elements). Just a reminder: if you can, it is always better to use native HTML elements. They provide a ton of behind the scenes functionality that would take a lot of extra work and code to implement correctly with a custom element.
Normally, focus behavior should not be added to anything that is not an element that users interact with. For example, it shouldn’t be added to headings or paragraphs. An exception to this is when you’re wanting to manage focus. A great example of this would be having a bar on the top where users can click a button (already has focus in the tab order with native HTML element button) that will take them to a heading. To this heading, you can provide an attribute of tabindex=”-1” and call the focus() method after the user has clicked on the button.
No hidden focus elements
There shouldn’t be any hidden focus elements on the page. An easy way to test this is to tab through your page. As elements are focused, they will have a focus ring (you can customize the behavior/ styling of the focus ring, more on this later) and should be visible on the page. If your focus ring disappears and you can’t find where the element is, you can check what is active with document.activeElement in the console. This will give you a reference to the element. If the element isn’t visual on the page, it needs to be removed from the tab order or made visible.
No keyboard trap
Users should not get to a place where they cannot tab out of. An exception to this is a temporary keyboard trap on things like modals to make sure they cannot tab outside before the task is complete.
Implementing a modal keyboard trap: an example
In HTML have a modal with some task (such as a confirmation or shopping cart modal). It would have similar class/ids as shown in the javaScript example.
JS:
// initialize variable to store the element users focused on before the modal popped up
let focusedElementBeforeModal;
// select the modal, model overlay, and modal toggle from the dom
const modal = document.querySelector('.modal');
const modalOverlay = document.querySelector('.modal-overlay');
const modalToggle = document.querySelector('.modal-toggle');
// when the modal toggle is clicked, we'll open the modal
modalToggle.addEventListener('click', openModal);
function openModal() {
// save current focus
focusedElementBeforeModal = document.activeElement;
// add event listeners to trap the tab key within the modal and close the modal if the overlay is clicked
modal.addEventListener('keydown', trapTabKey);
modalOverlay.addEventListener('click', closeModal);
// add event listeners too close the modal for specific items in your modal
const resumeShoppingBtn = modal.querySelector('#resumeShopping');
resumeShoppingBtn.addEventListener('click', closeModal);
// find all focusable elements in your modal
const focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]),
textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]';
let focusableElements = modal.querySelectorAll(focusableElementsString);
focusableElements = Array.prototype.slice.call(focusableElements);
// store first and last focusable elements to lock within
const firstTabStop = focusableElements[0];
const lastTabStop = focusableElements[focusableElements.length - 1];
// display modal and overlay
modal.style.display = 'block';
modalOverlay.style.display = 'block';
// focus first child element
firstTabStop.focus();
function trapTabKey(e) {
// check if the key pressed was tab
if (e.keyCode === 9) {
// check if it was shift + tab
if (e.shiftKey) {
// if we were already on the first, mode to last
if (document.activeElement === firstTabStop) {
e.preventDefault();
lastTabStop.focus();
}
// else if they just hit tab
} else {
// if we were already on the last element, we're going to move back to the
// first, completing the trap
if (document.activeElement === lastTabStop) {
e.preventDefault();
firstTabStop.focus();
}
}
}
// if the key they hit was esc instead of tab, we'll close the modal
if (e.keyCode === 27) {
closeModal();
}
}
}
function closeModal() {
modal.style.display = 'none';
modalOverlay.style.display = 'none';
focusedElementBeforeModal.focus();
}
Using skip links to save navigation
Skip links should be used so users can tab quickly to the main content in the page. This allows for quicker navigation for keyboard users and users with assertive technology.
Example code (This is just an example to start off with, actual implementation will look different):
HTML:
<!-- the a tag is before nav and other dom items -->
<a href="#maincontent” class=”skip-link”>Skip to main content</a>
<nav>
<!-- nav items -->
</nav>
<main id=”maincontent” tabindex=”-1”>
<!-- main content in the page -->
</main>
*note that the href and the id in the main are the same.
CSS:
/* make sure the color stands out against the page
and the link is placed outside of the page to start */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #BF1722;
color: white;
padding: 8px;
z-index: 100;
}
/* when focus is on the link, it will move into view */
.skip-link:focus {
top: 0;
}
This is a great article on skip links and the website itself is a great example of both skip links and tab order.
Semantics
One major goal with web content is to enable users to interact with your page with as little training as possible. We use affordances to build meaning.
Graphical Affordances
Users should be able to look at a design to determine what it does. For example, buttons for clicking and sliders for scrolling should generally look like what users expect them to look like. If a user cannot figure out that your button is a button, it is not providing enough graphical affordance. Other examples of graphical ui affordances include items that mimic real life things users might see, such as a checkbox. They’ve likely seen them on ballets or on other forms they might have filled out in different settings.
Affordances for non sighted users
Information should be expressed in a way that it can be accessed by assistive technology.
Screen Readers and other assistive technology will use the accessibility tree to create a user interface. This accessibility tree comes from the browser. The browser essentially takes the DOM tree and modifies it in a way that is useful to the assistive technology. It takes out all of the style and visual only elements, presenting users with only the content they need.
The screen reader will announce an element’s:
Name: name label, title, and text alternative all relate to the name
Role: what kind of element it is (ex: button, checkbox, edit text)
Value: what users have input
State (ex: checked or unchecked for checkboxes, selected, collapsed, etc.)
Labeling Content
The following traits need to be implemented in HTML:
-
All input elements need to have a label (so their name is discoverable)
- Visible labels are provided both for sighted users and non sighted users
- We can use a label for element or wrap the input in a label, either works
- If no visible label is needed, a text alternative should be used
-
Images are required to have an alt attribute.
- If the image is simply decorative, the alt tag can be empty (alt=””)
- Otherwise, the alt text must be descriptive.
- With no alt, screen readers will have bizarre behavior such as reading the file name.
Screen Reader Tips
When you’ve finished making sure your webpage’s tab order seems correct, try out a screen reader next! Mac’s have a built in Screen Reader called “VoiceOver” under the accessibility section. There is a training you can do with it that will guide you through the very basics of using it, I highly recommend checking it out! There are screen readers available on all systems so if you are working on a different one, a quick google search should provide you with some great resources on those.
Screen readers read directly from the DOM order, not the visual order. Fixing the tab order should have helped this, but there may need to be fine tuning for elements that were not focusable.
Link text needs to be descriptive. Users should know just by looking at the link what they will be getting. Screen readers have the ability to jump to all of the links or quickly navigate content so we need to make sure every link is clear and descriptive.
Page Landmarks:
Landmarks are a big deal with screen readers and aid in quick navigation. They help users find the semantics of the region of a page.
Landmarks that can and/or should be included:
-
main
- There should typically be only one main element that contains the main content of a page
header
footer
nav
-
article
- Self contained sections of content such as a blog post, news article, etc.
-
section
- A generic section of an application
- Usually, we put a heading inside to add details
-
aside
- Content that is tangentially related to the content around it such as a “fun facts” section
ARIA
As W3 states on their page, bad ARIA is worse than no ARIA. Do not use ARIA if native HTML will fit your user’s needs. Native elements give you semantics, keyboard support, and focus essentially for free where building the same thing in ARIA will take a lot of code and a lot of time.
ARIA or WAI-ARIA stands for Web Accessibility Initiative Accessible Rich Internet Applications. It allows you to specify attributes on elements and modify how that element is translated into the accessibility tree. In fact, all aria changes is the accessibility tree.
ARIA does not:
Modify the element’s appearance
Modify the element’s behavior
Add focusability
Add keyboard event handling
ARIA Roles
Roles in accessibility explain particular UI patterns. Roles such as “checkbox” give users of screen readers an idea of how they should interact with this piece of content. Reminder: HTML gives roles for free, when in doubt, stick to HTML.
See W3 for a list of ARIA roles and what is required to implement them should you need to build a custom element.
Labeling with ARIA
ARIA-label can be used to add a label to anything that has a visual representation of what a UI element is where a description might be needed for screen readers. For example, a hamburger menu might have an aria-label=”menu”.
ARIA-labelledby allows us to label elements that cannot be labelled with a label tag (such as a generic div).
<div aria-labelledby=”label1”</div><span id=”label1”>I'm a label</span>
ARIA-labelled by does not give you the clickablity label gives and overrides label as well as aria-label.
ARIA-live
Should there be something you need to alert your screen reader users about, ARIA live provides good options.
-
aria-live=”assertive”
- alert happens immediately, interrupting whatever the user was doing
-
aria-live=”off”
- you do not have to declare this, this is the default state, no alerts will happen
-
aria-live=”polite”
- alerts user after anything in progress is done
There are three attributes which work with aria-live to fine tune what is communicated to the user
-
Aria-atomic:
- Indicates whether the entire region should be considered as a whole when communicating updates
-
Aria-relevant:
- Indicates what types of changes should be presented
- Additions: any element being added to the live region is significant
- Removals: removing text or descendant
- Text: text content being added/changed
- All: everything
-
Aria-busy:
- Don’t alert in this time, such as loading
Style
For AA, a minimum contrast of 4.5:1 is required for all text and images. Large text (18 point or 14 point bold) can be lowered to a minimum of 3:1
For AAA, the minimums are 7:1 overall and 4.5:1 for large text.
We should expect an average of 1 per every 20 users to have some sort of color vision deficiency, with that in mind, information needs to be conveyed in more ways than color. For example, icons should be presented in different styles and not just different colors. Links need at least a 3:1 contrast from surrounding text and an additional differentiation is needed when the link is hovered over or receives focus (underline for example).
Responsive design
Even if you expect your users to only use one device (desktop for example), you should design with responsiveness in mind. As users zoom in, zoom out, or use a different design, the UI should respond and the web page should be usable.
Use %, em, and rem instead of pixels
-
Design with a responsive grid
- Use a meta viewport tag with width set to device-width and initial-scale set to 1.
<meta name="viewport" content="width=device-width, initial-scale=1">
With width, we are telling the viewport to match the width in device independent pixels
With initial-scale, we are setting a 1:1 ratio between CSS pixels and device independent pixels
-
DO NOT set max-scale to one or user-scalable to no. These are anti-patterns.
- Make sure you UI interactive elements have appropriate spacing around them to where they do not overlap and have enough padding to where users can click them when they’re mobile/touchscreen friendly.
Set the touch target to a minimum size of 48 device independent pixels. (This can include empty padding for smaller icons)
Set the margin around the touch target to a minimum of 32 device independent pixels to avoid users accidentally clicking one target while trying to click a different element.
Bonus: Styling the focus
This is not required for ADA compliance, but is definitely a nice touch and doesn’t take too much effort.
In CSS, you can use the pseudoclass :focus to style the focus ring all users can see (to see the focus ring, you will just tab through the page and everything it lands on will have a ring around it. If you don’t see the ring, you’ll need to check the tab order).
Example of pseudoclass and a basic focus ring:
:focus {
outline: 1px dotted #FFF
}
*Do not set the outline to 0. Focus elements should be obvious.
For consistency, it is recommended that you use box-shadow instead of outline. In addition, if you already have CSS for hover, you can add most of focus to that so it behaves similarly to hovering.
Example of how you might use hover styling with focus:
/* we want both hover and focus to look similarly here, but only focus to have the ring */
button:hover, button:focus {
background: #E91E63;
color: #FFFFFF;
text-decoration: underline;
}
/* here we're taking out the outline, but replacing it with a box shadow*/
/* we only want the focus ring to display when we're focused on it, not hovering*/
button:focus {
outline: 0;
box-shadow: 0 0 8px 3px rgba(255, 255, 255, 0.8);
}
Resources/tools I find very valuable
MVPS:
-
- This is such an important tool for evaluating a webpage. It really helps put success criteria to the WCAG and makes evaluation more simple
-
- This website is very informative and a solid example for a lot of accessibility concepts. All of the articles I’ve read here are straightforward and super helpful.
-
Udacity Web Accessibility Course
- This is a pretty quick course provided for free from Google engineers. It’s an amazing resource and will help you get the basics of web accessibility. I highly recommend completing that course.
-
WAVE Evaluation Tool or Lighthouse
- Both are very good tools for quickly assessing simple errors and color contrast in web pages. They are limited and most of the assessing will need to be done by hand, but these are wonderful starting places.
-
How To Do an Accessibility Review
- This article and accompanying video provide a great cheat sheet for conducting an accessibility review once you understand the basics.
Each of the above resources link to a ton of other helpful resources. For the purpose of this article, I wanted to keep the list smaller to avoid overwhelming. These five are definitely plenty to get started with.
Conclusion
We covered a lot in here! This is a great place to get started with accessibility, but remember that there is still a lot more to accessibility. If you take anything away from this, let it be that accessibility is all about enabling more users to access our content. It’s about user experience more than checking off a box.
Top comments (4)
Amazing article.
I just wish even on this forum, when people posting tutorials, instead of post a screenshot of the code they're talking about, they just copy paste the code, that alone would make the life much easier for screen reader users like myself.
Thanks once more.
amazing article. Literally all the pain points summed up here.
Thank you! I did my best to make it as comprehensive as possible while also keeping it at least somewhat short. I appreciate the feedback! :D
Great article