Rich Internet Applications - How to Make them Accessible

Post on 05-Sep-2014

676 Views

Category:

Internet

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Making rich internet applications accessible has been made easier through the introduction and support of WAI-ARIA. This presentation provides and introduction to WAI-ARIA and how to successfully use it to make interactive web applications accessible

Transcript

Rich

Internet

Apps –

How to

Make

Them

Accessible

Dylan BarrellTwitter: @dylanbarrell, @unobfuscatorGitHub: dylanbhttp://unobfuscated.blogspot.com/

8 trillion

$8 trillion

15%

1 billion

POUR

PerceivableOperableUnderstandableRobust

Call a Spade a Spade

RoleNameState(s)Value

Keyboard (and gestures) – add graphic of a Braille keyboard

• Accessibility and the DOM– DOM tree

• Semantic structure• Styled with CSS• Mouse and Keyboard behavior implemented by

browser• Default mapping to the accessibility tree

– Accessibility tree• Representation of the accessibility information• Each element has a name, a role, a value and a

state• Interpreted by Assistive technology• Used in combination with the Accessibility API

Insert periodic table of ARIA roles

• ARIA roles:– Provide the ability to control the

transition between application (forms) mode and document mode

– Provide more native announcments for widgets like menus, tabs, sliders etc.

– Provide for the ability to control announcements when updates occur away from the focus

– Provide much more control over the structure of the document and how someone navigates around it

<div id=”myId" class=”…”><button class=”…” id=”…”role="slider”aria-labelledby=”sliderLabelID”aria-valuemin="0" aria-valuemax="100”aria-valuenow="0" aria-valuetext="0%”></button>

</div>

• Adding role:– Changes the mapping to the

accessibility API– Does not change the behavior• Focussability• Keyboard interaction• Mouse interaction

– Does not change the appearance

<div id=”myId" class=”…”><button class=”…” id=”…”role="slider”aria-labelledby=”sliderLabelID”aria-valuemin="0" aria-valuemax="100”aria-valuenow="0" aria-valuetext="0%”></button>

</div>

Insert periodic table of ARIA attributes

• ARIA attributes:– Solve the problem of multiple labels and

descriptions through the addition of finer-grained labeling attributes

– Enhance the ARIA roles through the addition of standard state, value and role-specifying attributes

– Add some attributes for better control of what is spoken by the screen reader versus what is simply there for presentational purposes

<div id=”myId" class=”…”><button class=”…” id=”…”role="slider”aria-labelledby=”sliderLabelID”aria-valuemin="0" aria-valuemax="100”aria-valuenow="0" aria-valuetext="0%”></button>

</div>

<div id=”myId" class=”…”><button class=”…” id=”…”role="slider”aria-labelledby=”sliderLabelID”aria-valuemin="0" aria-valuemax="100”aria-valuenow="0" aria-valuetext="0%”></button>

</div>

<div id=”myId" class=”…”><button class=”…” id=”…”role="slider”aria-labelledby=”sliderLabelID”aria-valuemin="0" aria-valuemax="100”aria-valuenow="0" aria-valuetext="0%”></button>

</div>

<div id=”myId" class=”…”><button class=”…” id=”…”role="slider”aria-labelledby=”sliderLabelID”aria-valuemin="0" aria-valuemax="100”aria-valuenow="0" aria-valuetext="0%”></button>

</div>

<div id=”myId" class=”…”><button class=”…” id=”…”role="slider”aria-labelledby=”sliderLabelID”aria-valuemin="0" aria-valuemax="100”aria-valuenow="0" aria-valuetext="0%”></button>

</div>

<div id=”myId" class=”…”><button class=”…” id=”…”role="slider”aria-labelledby=”sliderLabelID”aria-valuemin="0" aria-valuemax="100”aria-valuenow="0" aria-valuetext="0%”></button>

</div>

handled = false, $this = jQuery(this);

if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) { // not interested return; } /* * Open a sub-menu and place focus on the first menuitem within it */ function openMenu() { if($this.hasClass("a11yfy-has-submenu")) { $this.addClass("open").attr("aria-expanded",

"true").find(">ul>li:visible").first().attr("tabindex", "0").focus(); $this.attr("tabindex", "-1"); } } /* * Move the focus to the menuitem preceding the current menuitem */ function prevInMenu() { var $context = $this; $this.attr("tabindex", "-1"); while (true) { if ($context.prev().is(':visible')) { $context.prev().attr("tabindex", "0").focus(); return } $context = $context.prev(); if (!$context.prev().length) { $context = $this.parent().find(">li").last(); if ($context.is(':visible')) { $context.attr("tabindex", "0").focus(); return } } if ($context[0] === $this[0]) { $this.attr("tabindex", "0") break; } } } /* * Move the focus to the next menuitem after the currently focussed

menuitem */ function nextInMenu() { var $context = $this; $this.attr("tabindex", "-1"); while (true) { if ($context.next().is(':visible')) { $context.next().attr("tabindex", "0").focus(

/* * This implements the WAI-ARIA-PRACTICES keyboard functionality

where * pressing the key, corresponding to the first letter of a VISIBLE element * will move the focus to the first such element after the currently

focussed * element */ var keyCode = e.charCode || e.which || e.keyCode, keyString = String.fromCharCode(keyCode).toLowerCase(), ourIndex = -1, currentItem = this, $this = jQuery(this), $nextItem, $prevItem, $menuitems = $menu.find("li[role=\"menuitem\"]:visible");

if (keyCode === 9) { return true; }

$menuitems.each(function(index, value) { if (value === currentItem) { ourIndex = index; } if (index > ourIndex && !$nextItem) { if (jQuery(value).text().trim().toLowerCase().indexOf(keyString)

=== 0) { if (ourIndex !== -1) { $nextItem = jQuery(value); } else if (!$prevItem) { $prevItem = jQuery(value); } } } }); if (!$nextItem && $prevItem) { $nextItem = $prevItem; } if ($nextItem) { $nextItem.attr("tabindex", "0").focus(); $this.attr("tabindex", "-1"); if ($nextItem.parent().get(0) !== $this.parent().get(0)) { $this.parent().parent("li").removeClass("open").attr("aria-

expanded", "false"); } } e.stopPropagation(); }).on("keydown", function(e) { /* * This implements the WAI-ARIA-PRACTICES keyboard navigation

functionality */ var keyCode = e.which || e.keyCode,

} else { /* If in sub-menu, open sub-sub-menu */ openMenu(); } break; case 40: //down handled = true; if ($this.parent().hasClass("a11yfy-top-level-

menu")) { /* If in menubar, open sub-menu */ openMenu(); } else { /* If in sub-menu, move to the next menuitem

*/ nextInMenu(); } break; } if (handled) { e.preventDefault(); e.stopPropagation(); } return true;

); return } $context = $context.next(); if (!$context.next().length) { $context = $this.parent().find(">li").first(); if ($context.is(':visible')) { $context.attr("tabindex", "0").focus(); return } } if ($context[0] === $this[0]) { $this.attr("tabindex", "0") break; } } } switch(keyCode) { case 32: // space case 13: // enter handled = true; if ($this.find(">a").length) { if ($this.find(">a")[0].click) { /* If this is a leaf node, activate it*/ $this.find(">a")[0].click(); } else { // This is a hack for PhantomJS $this.find(">a").first().trigger("click"); } } else { /* If it has a sub-menu, open the sub-menu */ openMenu(); } break; case 37: //left case 27: //esc handled = true; if (keyCode === 37 && $this.parent().hasClass("a11yfy-top-level-menu")) { /* If in the menubar, then simply move to the previous menuitem */ prevInMenu(); } else { if ($this.parent().attr("role") === "menu") { // this is part of a submenu, set focus on containing li $this.parent().parent().attr("tabindex", "0").focus() .removeClass("open").attr("aria-expanded", "false"); $this.attr("tabindex", "-1"); } } break; case 38: //up handled = true; if ($this.parent().hasClass("a11yfy-top-level-menu")) { /* If in the menubar, then open the sub-menu */ openMenu(); } else { /* If in sub-menu, move to previous element */ prevInMenu(); } break; case 39: //right handled = true; if ($this.parent().hasClass("a11yfy-top-level-menu")) { /* If in menubar, move to next menuitem */ nextInMenu();

First ARIA Best Practice – If there is a native HTML element that does

the job, use that

Examples1. Use <button> and <input

type=“submit”> NOT <a role=“button”>

2. Use <ul>, <ol> and <li> NOT <span role=“list”> etc.

Compelling ARIA roles• Landmark Roles

– main, search, navigation, contentinfo, complementary, banner

– region in combination with aria-label

• Live Region Roles– log, status, alert

• Some Widget Roles– tabpanel and tab– slider– menu, menubar, menuitem and associated attributes– dialog – in combination with the document role to get it

to work in NVDA– tree and treeitem – a bit tricky to get to work reliably

• Some form roles– button, textbox, checkbox, radio, radiogroup

• presentation role

Second ARIA Best Practice – test it on all YOUR platforms with the assistive technology YOU must

support

All platforms have problems, most have workarounds, iOS is the

most problematic and Android is not quite ready for prime time

yet

ARIA holes• Tables, tables, tables– Use the a11yfy library

• Arrow keys on iOS– Insert dynamic modal content in line– Use gestures

• Gestures– Think hard about your mapping to the

portable gestures– add on screen controls where possible

Accessible Gesture Calendar Examplehttps://github.com/dylanb/gestura11yhttp://dylanb.github.io/datepicker/datepicker.html

• Shows use of tabindex to control focus• Shows use of role=“application” to force

application mode• Shows use of aria-live regions to announce the

current date as the user moves around• Shows use of aria-hidden to hide presentation

markup from the screen reader• Shows use of keyboard handler and mapping to

gestures• Shows how to ensure that gestures are

consistent regardless of zoom level

Accessible Gesture Calendar Examplehttps://github.com/dylanb/gestura11y

Third ARIA Best Practice – Always attach your event

handlers to the same element that has the role and the

focus

If you stick to this rule, you will avoid events not being delivered consistently

Fourth ARIA Best Practice – In complex widgets like

menubars, tabpanels etc. always make all interim

structures presentational

Fifth ARIA Best Practice – in a complex widget where you

are managing focus, disable all naturally focusable

elements with tabindex=“-1”

Example is the a11yfy menu examples where the anchors

are given tabindex=“-1”

FinallyThere is a wealth or resources including

The ARIA specification (recommendation, normative)http://www.w3.org/TR/wai-aria/

The Authoring Practices (draft) http://www.w3.org/TR/wai-aria-practices/

Using ARIA in HTML (draft, informative)http://www.w3.org/TR/aria-in-html/

The WAI Web Site http://www.w3.org/WAI/intro/aria

Mozilla Developer Network https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA

top related