Web Accessibility - a term often overlooked in the early days of the web which is gaining more and more prevalence every day. Since the technological ecosystem evolved in a way in which it ended up in everyone's hands, regardless of where or who they are in the world, and the web being a core part of almost every piece of technology - the idea that the web should be well designed for everyone gained more traction and is a well regarded standard in many places and institutions nowadays. That's what accessibility means -> making something easily accessible and removing as many hurdles as possible imposed by environmental or physical conditions. In this article, we'll touch on many general accessibility ideas which can be transferred to other tech areas as well, but we'll be drilling down on Web Accessibility specifically from the perspective of a Software Developer or Quality Assurance Engineer.
While the Americans with Disabilities Act does not specifically address Website accessibility specifically, historically disputes or lawsuits were highly in favour of companies which abided by the Web Content Accessibility Guidelines (WCAG 2.1) - so much so that it basically became the norm for designing highly accessible UIs.
While the guidelines are very well described, the document can be difficult to navigate through - thus a more practical resource to reference while building a compliant experience is the WebAIM's WCAG 2 Checklist with references to the original document.
A list of useful links:
Common acronyms used throughout article:
A good thing to keep in mind while developing accessible apps is the P.O.U.R. principles (Perceivable, Operable, Understandable, Robust). Whenever working on a change or feature, it’s good to form the habit of asking yourself if your work complies with these principles.
The POUR principles are generally achievable in most cases - and a good way to make sure this happens is to split the a11y compliance work into 3 main categories.
Building with good semantics and maintaining them consistent throughout the application is most crucial aspect of a11y and the one that should be addressed first - as it solves a great deal of issues most of the time in the most common situations.
Similar to the DOM, the browser creates an Accessibility Tree. Just like the DOM gets translated to a visual representation of your semantics on the screen, the Accessibility Tree gets translated to other types of representations understandable by assistive technology, such as screen readers.
Semantics can be a deep-dive topic, but at the end of the day it generally boils down to using the right HTML elements and attributes. The most important types of elements to keep in mind are:
Focus determines where the keyboard / assistive technology events go on the page. All interactable elements should be focusable and navigatable in a logical and coherent fashion through keyboard inputs and assistive technology inputs.
A few important principles to keep in mind:
The website’s design should be easily perceivable and interactable by people with certain visual or motor impairments. This can be achieved through paying attention to a few aspects such as:
A11y compliance on a website is not a yes or no. A website/application can be less or more accessible -
There are tools that help us check for a11y issues. While they are recommended and very helpful, they will not manage to detect some issues in more complicated modern UI design patterns. For example, it is easy for a tool to figure out wether the contrast between the color of a text and it’s background high enough, but is virtually impossible to figure out wether your new fancy custom date-picker component is easily navigable by a SR user and makes sense to them. The first example is deterministic - as it can follow a strict rule which can always be applied the same way, but the second one is much less so - any two custom date-pickers from two different applications may have completely different behaviour so we would have to judge if the experience provided is accessible enough or not.
That being said, we should use tools for checking a11y, but we should also manually check and make decisions regarding what an accessible experience should be.
The most popular a11y testing tool is aXe: axe DevTools - Web Accessibility Testing
A good start would be here: Getting started with the axe DevTools extension
Another good one is Chrome dev tools' built-in “Lighthouse” tab. A good overview of how it works can be found here (content is a bit outdated, you don’t need to manually enable it anymore): The new way to test accessibility with Chrome DevTools - A11ycasts #23
Performing these steps below will generally reveal most a11y issues in the most common cases, but do remember that manually auditing a website involves making decisions and judgement calls along the way as there are no strict rules about how any given custom non-standard component should behave. We will have to decide if a certain section of our website is accessible enough or not based on our experience during the audit.
A very handy resource to reference while performing audits is WebAIM: WebAIM's WCAG 2 Checklist. While it is not a definitive guide, it does a very good job of condensing the most important aspects of WCAG2.
By default the natural tab order is identical to the order of the elements in the DOM. This means that if we build our DOM in a comprehensive manner according to our content, we will generally have pretty good results in terms of a11y compliance. However, this is not always possible and situations in which you will have to manage focus are common in modern SPAs. A few examples may include:
The tabindex attribute enables us to manage page elements' focus in a custom manner. It also enables handling focus related functionalities for elements which are not focusable by default.
A tabindex value of higher than 0 is considered an anti-pattern. While it modifies the natural tab order for regular users, it will not affect the order in which SRs interpret the content, thus creating inconsistencies experiences between different users navigating in different ways.
Check out this example which shows the difference between how a set of native buttons differs from a set of custom ones (low a11y), as well as the fixes for the custom ones to make them more accessible.
Code example: A11y - Custom Buttons
In cases in which we may not be able to use native controls or proper semantics when writing our applications, we should ensure that the end result will still provide an accessible experience. Thus, we should pay attention to “decorating” our HTML with the proper aria-* and role attributes which convey more underlying information to SRs and other assistive technology about what the your code is supposed to do.
A very helpful resource to reference is the WAI-ARIA Authoring Practices 1.1 which tells us exactly what to take into account when implementing common patterns and widgets and how they should behave. It describes how the Keyboard Interaction should behave and which WAI-ARIA Roles, States, and Properties you should use.
The best way to understand how to use this document is by example. In the below example you can see a custom implementation of a Radio Group without using the native <input type=”radio”> - to achieve that we should reference the Radio Group definition - WAI-ARIA Authoring Practices 1.1. Based on the specifications, you can see a side-by-side comparison of a native implementation, a custom one with low a11y, and a custom one with high a11y:
Code example: A11y - Custom RadioGroup
A highlight of the most commonly used aria-* labels can be found below:
<div id="menu" aria-owns="submenu">...</div>
<div id="submenu">...</div>
<label for="pw">Password</label>
<input type="password" id="pw" aria-describedby="pw-help">
<div id="pw-help">Password must have at least 12 characters</div>
<div class="timepicker" aria-atomic="true">
<input type="number" id="hours" value="12">
<input type="number" id="minutes" value="30">
</div>
A full list of all {{{aria-*}}} attributes can be found here: ARIA Attributes
A full list of the role definitions can be found here: Role Definitions
Here you can find guides for some of the most commonly used SRs:
Since a11y is not something you need to tackle every single day as an web engineer, it's easy for your grasp on the core concepts to loosen over time and forget things. I initially wrote this as a cheatsheet for a project's dev team to use when developing frontend applications which needed an extra degree of care on the a11y side of things. But it grew more and more over time and got to a point in which it was ready to be turned into an article and shared with the world. At Quickleaf, we still reference it to this day and do our best to keep it updated. I hope many of you will find it useful!