Making Accessibility Simpler, With Ally.js
I’ve been a web developer for 15 years, but I’d never looked into accessibility. I didn’t know enough people with (serious) disabilities to properly understand the need for accessible applications and no customer has ever required me to know what ARIA is. But I got involved with accessibility anyway – and that’s the story I’d like to share with you today.
At the Fronteers Conference in October 2014 I saw Heydon Pickering give a talk called “Getting nowhere with CSS best practices”. Among other things, he made a case for using WAI-ARIA attributes like aria-disabled=“true”
instead of classes like .is-disabled
to express application state. It struck me then and there that I was missing out on a few well-prepared standards, simply because ARIA belongs to that accessibility space that I had no idea of.
After talking to Heydon a bit more I finally understood that ARIA could help me write web applications without having to bike-shed class names for various states (is the thing disabled, is it visible, is it still loading…). The discussion did not touch on accessibility at all – we were simply talking about how to make web development a tiny bit simpler.
I decided I needed to dig into ARIA – honestly not because I deeply cared about accessibility, but because I had no intention of reinventing the wheels they already had. One of the first things you’ll learn when looking at ARIA is that supporting keyboard navigation is fundamental. And the first step to understanding keyboard navigation is to understand what focus is. And this is where I tripped, because nobody knew (in detail) which elements could receive focus and which could not.
Having had a bit of experience testing browser compatibility (“CSS3 Transitions: Thank God We Have A Specification!”), I decided I would spend some time investigating. An ebook covering my findings is in the works and will be ready to make you lose focus in early 2016. But more importantly, the JavaScript variant of that book is available today:
ally.js Highlights
Before we get into why and how this project came to be, here’s a short list of things it can help you with:
- ally.js fixes browser bugs concerning
:focus
in Internet Explorer and WebKit. - ally.js provides high-level tools to disable interactive elements and hide entire branches of the DOM from screen readers.
- ally.js provides a simple way to prevent browsers from scrolling an element into view when it’s about to be focused.
- ally.js helps styling
:focus
by providing a:focus-within
polyfill and the ability to distinguish mouse focus from keyboard focus. - ally.js not only helps you understand which elements are focusable and which are keyboard-focusable, but also the tabbing order.
ally.js includes a few shims and a polyfill but does not have any major dependencies. It’s designed to be compatible: UMD, AMD, CommonJS, ES6, modules or bundled – it’s your choice.
Show Me Some Code!
When making your application keyboard accessible, it is important to hide elements from the keyboard that can currently not be interacted with. This may be the case when a modal dialog is visible, or the off-screen menu is shown. We can easily disable everything outside of our dialog:
// disable everything that is not a child of #our-dialog
var handle = ally.maintain.disabled({
filter: '#our-dialog',
});
// re-enable everything that we disabled previously
handle.disengage();
The same principle is true for any content (not just the interactive kind) to make sure screen reader users don’t get lost. We can easily hide everything outside of our dialog:
// hide everything that is not a child of #our-dialog by adding aria-hidden="true"
var handle = ally.maintain.hidden({
filter: '#our-dialog',
});
// re-enable everything that we disabled previously
handle.disengage();
Sometimes we need to act on specific keys like Enter and Escape:
var handle = ally.when.key({
enter: function(event) {
// handle the enter event
},
escape: function(event, disengage) {
// handle the escape event…
disengage();
},
});
// stop listening for keys
handle.disengage();
Motivation
Let’s have a look at why I thought it was necessary to create something new in the first place. While there are various reasons, these are the important ones:
- Many (especially older) articles sport code examples and approaches that are not easily comprehensible and promote coding practices that by today’s standards would be considered harmful.
- Even the good articles usually only focus on accessibility, ignoring everything else that’s relevant to creating compelling websites and applications.
- Literally no articles and resources share code. There doesn’t seem to be much collaboration (on code) outside of individual projects, leading to the same thing being coded over and over again.
- Many problems don’t seem well understood, or not considered a problem to begin with.
- In a few aspects accessibility feels undeterministic. In virtually all cases concerning semantics we’re in a state that feels like the early 2000s: you might have created something conforming to standards, but that doesn’t mean it works everywhere – or even anywhere at all.
In the end I felt like we were missing a proper toolbox. Like jQuery is to conquering the DOM without having to care much about browser compatibility, be they gaping holes or subtle bugs. Like D3 is to conquering interactive data visualization. Or like RaphaelJS was to conquering SVG only a few years ago. I couldn’t find anything similar that would do the heavy lifting for accessibility, at least nothing comprehensive and framework-independent.
Execution
I have a few principles that guide the way I work:
- If you don’t understand the problem, you’re not creating solutions. Research is key.
- Start small, build over time.
- Complex solutions don’t change the world. Simplicity is key.
- One person can only do so much. Collaboration is key.
Research Is Key
Before you can write a single line of code to do something, you should have a pretty good idea what that line of code is supposed to do. If you only solve the problem at hand, you’re likely missing the bigger picture. Without the bigger picture in front of you, creating lasting solutions is incredibly hard, if not next to impossible.
Once I realized that neither I nor the internet was able to answer the simple question of which elements can take focus, there was only one option left: rolling up my sleeves and figuring out what browsers actually do. This led to a compatibility table detailing what browsers consider focusable, a comparison of focus styles and a slew of filed bugs.
Start Small
Throughout the past 14 months I managed to keep focus on keyboard navigation. Not losing myself – or the library – in too much of ARIA’s semantics. Doing one thing and not starting anything new until you’re done isn’t easy, especially not while you’re learning a dozen new tricks a day.
Starting small also meant limiting browser scope. I didn’t need older Internet Explorer and Android browsers, so version 1.0.0 doesn’t support anything below IE10 and Android 4.4. Version 1.1.0 will add support for IE9, a reasonable second step.
Simplicity Is Key
If you want people to use your tools, you need to make sure that your tool makes sense to them, preferably without requiring a degree in rocket science. But how do you hide a tool’s internal complexity to make it seemingly simple?
- Provide a consistent and memorable API.
- Provide documentation that not only explains how to use a feature, but why it’s necessary in the first place.
- Meticulously expose all edge cases in the documentation to prevent people from having to debug your code.
- Make consuming your tool a breeze. AMD and CommonJS can be generated from ES6. Modules can be bundled and exposed as UMD.
- Provide tutorials that explain how your tool’s features work together to solve particular problems.
- Provide ways to quickly experiment with your tool’s features without having to install the internet first.
Collaboration Is Key
I’ve mustered all my spare time in the past 14 months and threw it at my open source projects. I’m not going to lie to you: it was rough and I’m certain I won’t be able to keep this up. To prevent a one-man-show failure the project will need to find and involve like-minded folks. But collaboration is a multifaceted topic.
The core contributors are people who spend time on the project on a regular basis. This is the rarest form of contribution, as it takes the highest commitment. Because of that I’m incredibly happy to welcome Marcy Sutton on board! In many ways Marcy has much more experience in the accessibility world than I do, so her addition to the team is our first big win. To make sure more people can chime in, everything we do is documented.
It’s quite common for people to submit smaller patches to source code and documentation. Because a single person is likely to only contribute a handful of changes, we like to call them drive-by contributors. For them it is important to be able to make their changes quickly and safely. That’s why all of the documentation pages have convenient links to open issues, edit pages and point to related resources (source files, documentation, tests).
And then there’s the group of people who aren’t contributing to the project’s code, more so to its success. The integrators are very important people, as they’re taking charge in amping up other projects by adding ally.js features to them. Currently we’re talking with the folks of jQuery UI and Angular’s ngAria about how to best support their efforts by offloading things to ally.js. A few people from the React community have already voiced an interest as well.
Everything we do within the ally.js space has the intention of improving the status quo for everyone, even and especially for people not using the library. The browser bugs we’re filing and the discussion around improving our web standards are all based on the research we’re doing to improve the library. However you won’t be surprised to find the library moving much quicker than web standards at large.
The Future
Of the three columns of accessibility – keyboard support, semantics, and flexible UI – ally.js currently only covers the first. With the insights Marcy brings with her (and maybe a few more minds) we intend to dive into the semantics pillar. Understanding ARIA is one thing, but understanding what browsers and screen readers actually do with it is quite a different story.
We’ll be looking at providing simple APIs for ARIA for your imperative needs. We’ll investigate options to automate enforcing semantics like these “Tips for Creating Accessible SVG” at runtime and within your build process.
We’ll be looking at how to enhance your use of ARIA by providing you with extended keyboard support for common widgets (like the listbox).
Conclusion
You can care about accessibility issues without being affected by a disability yourself. In many ways, making your apps and sites accessible benefits everyone. ally.js helps you accomplish that.
ally.js is positioning itself as a center for collaborating on accessibility-related features, by providing low-level tools to other libraries and frameworks as well as high-level functions to developers. If we start working together we might just get somewhere…
Further Reading
- Accessibility APIs: A Key To Web Accessibility
- Accessibility: Improving The UX For Color-Blind Users
- Notes On Client-Rendered Accessibility
- Accessibility: Improving The UX For Color-Blind Users