On Github fuzzbomb / js-a11y-intro-slideshow
Backend developer at Annertech
Contributor at Drupal project
Twitter: @martianwebdev Github: fuzzbomb
W3C Web Acessibility Initiative (WAI)
Web Content Accessibility Guidelines 2.0 (WCAG)
"POUR"
WCAG is organized as a set of success criteria, each describing an accessibility practice in terms of:
Example: SC 1.3.1 Info and Relationships describes the use of headings and labels to indicate the structure of a page.
... because this talk is for JS developers!
... because there isn't time,
... but these things are still important topics.
Note: content authors/editor's decisions are just as important as designers and developers.
Actually, I love talking about this. Just not today.
Let's start with an inaccessible example, then see how we can improve it.
We'll make a mobile menu button - a.k.a "Burger Menu"
Git repo: fuzzbomb/mobile-menu-a11y-demo
Improvements made during these slides are marked as git tags, which we'll refer to as we go along.
A working demo of the finished menu widget is also available.
Our button is a <div>, and our menu is a list of links.
<div id="main-menu"> <div id="main-menu-button"> <i class="fa fa-bars"></i> <span>Main Menu</span> </div> <nav> <ul> <li><a href="http://example.com/tech">Technology</a></li> <li><a href="http://example.com/science">Science</a></li> <li><a href="http://example.com/arts">Arts</a></li> </ul> </nav> </div>
Bind a click handler to our <div> to toggle menu visibility.
$(document).ready(function() { // Initialize. var menuDisplayed = false; $('#main-menu nav').hide(); // Add the open/close behaviour. $('#main-menu-button').click(function(event) { if (menuDisplayed === true) { $('#main-menu nav').hide(); menuDisplayed = false; } else { $('#main-menu nav').show(); menuDisplayed = true; } }); });
"Works with a mouse"
Just a few simple controls.
Not necessarily using assistive-technologyMight be a plain-old QWERTY keyboard.
Sighted keyboard users really need to be sure what element has focus, before they press enter.
Subtle focus styles don't work - they need to be clear. Beware of re-using mouse hover styles.
This doesn't limit your creativity - take inspiration from games consoles and Smart TV.
Allows quick access to interact with the page's main content, without traversing lots of sidebar links, or a header menu.
Who benefits? Primarily sighted keyboard users. (Screen-readers offer other ways to get around a page.)
Off-canvas != Off-viewport
Be careful. Elements rendered off-viewport can be a help or a hindrance...
Good:"Invisible" labels are still accessible to screen-readers.
Bad:Focusable elements are traversed by sighted keybpoard users, who can't tell what is in focus.
The menu widget we have built does not work for keyboard users at all. The expected behaviour is:
Press TAB until I can see the button has focus. Press space or enter to activate the button.<div id="main-menu"> <div id="main-menu-button" tabindex="0"> <i class="fa fa-bars"></i> <span>Main Menu</span> </div> // ... list of menu links </div>
Add a tabindex=0 attribute to our <div>.
Keyboard focus is now possible, but the button does not yet respond to keypress.
#main-menu-button { background-color: #444444; color: #ffffff; } #main-menu-button:focus { background-color: #ffffff; color: #444444; }
Use CSS to make it very obvious that the button has focus.
In this example, we invert the colour contrast.Avoid styles which are too subtle.
$('#main-menu-button') .keypress( function(event) { // Only respond to enter or spacebar keys if (event.which == 13 || event.which == 32) { // Spacebar usually triggers page scrolling. event.preventDefault(); $(this).trigger('click'); } }) .click(function(event) { // The open/close behaviour // ... });
Listen for keypress event, confirm which button was pressed, and trigger a click() event.
"Works with a keyboard"
Whoah. Learning curve.
Be kind to your colleagues :-)
Many ways to navigate or inspect a page...
WebAIM Screenreader user survey
<ul role=navigation>
main, banner, contentinfo, navigation,complementary, search, ...
New HTML5 elements - main, header, footer, nav, aside.
Re-cap. We already know this stuff...
Attributes which often contain rich semantics, but are really only useful to a human audience: developers!
None are understood by screen-readers.
We want machine-readable semantics
HTML is NOT a user interface language.
ARIA provides vocabulary of UI roles, states, and properties.
They express the range of interaction found in native Desktop and Mobile UI widget APIs.
Formal, machine-readable semantics.
Host-language semantics are preferred.
Use sparingly!
Aim to provide a screenreader user with an idea of what the button can be used for.
Describe the button:We were hiding the text label with CSS display:none (which prevents screenreaders from finding it) so we'll remove this.
-#main-menu-button span { - display: none; -}
The visuallyhidden class (from HTML5 Boilerplate) uses clip and overflow properties to hide the text in a 1px square box.
<div id="main-menu-button" tabindex="0"> <i class="fa fa-bars"></i> <span class="visuallyhidden">Main Menu</span> </div>
Now a screenreader can announce the button name.
<div role="button" id="main-menu-button" tabindex="0"> <i class="fa fa-bars"></i> <span class="visuallyhidden">Main Menu</span> </div>
Adding role=button to the <div> overrides the default HTML semantic, so screenreaders can announce it as a "button" (or sometimes "clickable").
We'll use two ARIA attributes in tandem. Note that both of these attributes need to go on the button element itself.
aria-controls needs an ID to refer to.
<div role="button" id="main-menu-button" tabindex="0"> <i class="fa fa-bars"></i> <span class="visuallyhidden">Main Menu</span> </div> <nav id="main-menu-nav"> <ul> ... list of links ... </ul> </nav>
$('#main-menu-button') .attr('aria-controls', 'main-menu-nav') .keypress( function(event) { /* Handle keypress */ }) .click(function(event) { /* The open/close behaviour acts on '#main-menu nav' */ });
$('#main-menu-button') .attr('aria-controls', 'main-menu-nav') .attr('aria-expanded', false) // NEW, initialize .keypress( function(event) { /* Handle keypress */ }) .click(function(event) { if (menuDisplayed === true) { $('#main-menu nav').hide(); $(this).attr('aria-expanded', false) // NEW menuDisplayed = false; } else { $('#main-menu nav').show(); $(this).attr('aria-expanded', true) // NEW menuDisplayed = true; } });
We initialize aria-expanded as false, to match the initial appearance of the menu, and update it whenever we show or hide the menu.
"Works with a screenreader"
Git tag: milestone-works-with-mouse-keyboard-screenreader (ad3fa57)
We actually broke the golden rule of ARIA. Avoid using ARIA semantics to provide a role, where HTML already provides the role with an equivalent element.
In our case we used:
<div role="button"></div>
When we ought to have used:
<button></button>
After replacing the <div role=button> with a real HTML <button>, we can remove a few things to simplify the code...
TL;DR... a11yproject.com
A community-reviewed set of practical tips, with a gentle learning curve. If you only read one thing from my reading list, make it this website.
In fact, you might do better perusing their resources list ;-)
A short open-source book which gives a great introduction to thinking about accessibility, along with techiniques.
Particularly useful for introducing personas when considering accessibility. For every technique, it has a discussion of who benefits, and how.
It's starting to look a little dated (19" is a large monitor!), and a few techniques have changed, but few books match this one as an introduction to the topic.
The End
Slides: fuzzbomb.github.io/js-a11y-intro-slideshowDemo code: github.com/fuzzbomb/mobile-menu-a11y-demo