Page 1
© 2014 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.
#WWDC14
Improving the Accessibility and Usability of Complex Web Applications
Session 516 Jesse Bunch Productivity Engineering
Media
Page 10
What You Will Learn
Page 11
What You Will Learn
Accessibility fundamentals
Page 12
What You Will Learn
Accessibility fundamentals
Latest research and statistics
Page 13
What You Will Learn
Accessibility fundamentals
Latest research and statistics
Accessibility standards
Page 14
What You Will Learn
Accessibility fundamentals
Latest research and statistics
Accessibility standards
ARIA and focus management
Page 15
What You Will Learn
Accessibility fundamentals
Latest research and statistics
Accessibility standards
ARIA and focus management
Common issues and solutions
Page 22
AccessibilitySupports real people with real needs by providing an alternate interaction model, like a keyboard or switch
Page 23
Universal DesignDesign so thoughtful that it works for everyone
Page 25
…ALIGNED PERFECTLY FOR AN INCREDIBLE SWING
Page 38
Visually impaired, worldwide285 Million
World Health Organization, 2013
Page 39
Completely blind, worldwide40 Million
World Health Organization, 2013
Page 40
Accessibility Standards
Page 41
Web Content Accessibility GuidelinesWCAG
Page 44
Perceivable
Operable
Understandable
Robust
Page 58
Use Semantic Markup
Page 60
Semantic Markup
Uses <div>
Page 61
Semantic Markup
Uses <div> Uses semantic headings
Page 62
Semantic Markup
<div style=“font-size: 18px;”> All About Widgets </div>
Page 63
Semantic Markup
<div style=“font-size: 18px;”> All About Widgets </div>
Page 64
Semantic Markup
<div style=“font-size: 18px;”> All About Widgets </div>
Page 65
Semantic Markup
<div style=“font-size: 18px;”> All About Widgets </div>
<h1>All About Widgets</h1>
Page 66
Semantic Markup
<div style=“font-size: 18px;”> All About Widgets </div>
<h1>All About Widgets</h1>
Page 67
Semantic Markup
<div style=“font-size: 18px;”> All About Widgets </div>
<h1>All About Widgets</h1>
Page 68
Use Standard Controls
Page 69
ControlsCustom slider
0 100
Page 70
ControlsCustom slider
<div class=“slider”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
0 100
Page 71
ControlsCustom slider
<div class=“slider”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouseel.addEventListener(“mousedown”, handleMouseDown);el.addEventListener(“mousemove”, handleMouseMove);el.addEventListener(“mouseup”, handleMouseUp);
0 100
Page 72
ControlsCustom slider
<div class=“slider”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouseel.addEventListener(“mousedown”, handleMouseDown);el.addEventListener(“mousemove”, handleMouseMove);el.addEventListener(“mouseup”, handleMouseUp);
// Touchel.addEventListener(“touchstart”, handleTouchStart);el.addEventListener(“touchmove”, handleTouchMove);el.addEventListener(“touchend”, handleTouchEnd);el.addEventListener(“touchleave”, handleTouchLeave);el.addEventListener(“touchcancel”, handleTouchCancel);
0 100
Page 73
<div class=“slider”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
Page 74
<div class=“slider”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
Page 75
<div class=“slider”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
// Keyboardel.addEventListener(“focus”, handleFocus);el.addEventListener(“blur”, handleBlur);el.addEventListener(“keydown”, handleKeyDown);
Page 76
<div class=“slider”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
// Keyboardel.addEventListener(“focus”, handleFocus);el.addEventListener(“blur”, handleBlur);el.addEventListener(“keydown”, handleKeyDown);
Page 77
ControlsNative slider
Page 78
ControlsNative slider
<input type=“range” min=“0” max=“100” value=“1”>
Page 79
ControlsNative slider
<input type=“range” min=“0” max=“100” value=“1”>
Browser Handles• Mouse events
• Touch events
• Keyboard events
• Tracking state
• Style updates for focus and blur
• Notifying observers
• Accessibility
Page 80
ControlsNative slider
<input type=“range” min=“0” max=“100” value=“1”>
Browser Handles• Mouse events
• Touch events
• Keyboard events
• Tracking state
• Style updates for focus and blur
• Notifying observers
• Accessibility
Page 81
ControlsCustom slider
<div> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
Page 82
<div> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
ControlsCustom slider
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
Page 83
ARIAAccessible Rich Internet Applications
Page 84
ARIACustom slider
<div> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
Page 85
ARIACustom slider
<div role=“slider”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
Page 86
ARIACustom slider
<div role=“slider” aria-valuemin=“0” aria-valuemax=“100”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
Page 87
ARIACustom slider
<div role=“slider” aria-valuemin=“0” aria-valuemax=“100” aria-valuenow=“50”> <div class=“left-label”> ... </div> <div class=“slider-handle”> ... </div> <div class=“right-label”> ... </div> </div>
// Mouse el.addEventListener(“mousedown”, handleMouseDown); el.addEventListener(“mousemove”, handleMouseMove); el.addEventListener(“mouseup”, handleMouseUp); !
// Touch el.addEventListener(“touchstart”, handleTouchStart); el.addEventListener(“touchmove”, handleTouchMove); el.addEventListener(“touchend”, handleTouchEnd); el.addEventListener(“touchleave”, handleTouchLeave); el.addEventListener(“touchcancel”, handleTouchCancel);
Page 88
ARIARetrofitting old content
Page 89
ARIARetrofitting old content
<div style=“font-size: 18px”> All About Widgets </div>
Page 90
ARIARetrofitting old content
<div style=“font-size: 18px” role=“heading” aria-level=“1”> All About Widgets </div>
Page 91
ARIAImplicit roles
// Implicitly gets role=“heading” and aria-level=“1” <h1>All About Widgets</h1> !
Page 92
ARIAImplicit roles
// Implicitly gets role=“heading” and aria-level=“1” <h1>All About Widgets</h1> !
// Effectively the same as a <div> tag <h1 role=“presentation”>All About Widgets</h1> !
Page 94
Focus Managementtabindex
Page 95
Focus Managementtabindex
tabindex=“0”Focusable with JavaScript, in default tab order
tabindex=“-1”Focusable with JavaScript, not in default tab order
No tabindexNot focusable with JavaScript, not in default tab order** Except for native controls and links
Page 96
Focus Managementtabindex
tabindex=“0”Focusable with JavaScript, in default tab order
tabindex=“-1”Focusable with JavaScript, not in default tab order
No tabindexNot focusable with JavaScript, not in default tab order** Except for native controls and links
Page 97
Focus Managementtabindex
tabindex=“0”Focusable with JavaScript, in default tab order
tabindex=“-1”Focusable with JavaScript, not in default tab order
No tabindexNot focusable with JavaScript, not in default tab order** Except for native controls and links
Page 98
Focus Managementtabindex
tabindex=“0”Focusable with JavaScript, in default tab order
tabindex=“-1”Focusable with JavaScript, not in default tab order
No tabindexNot focusable with JavaScript, not in default tab order** Except for native controls and links
Page 105
tabindex=“0”
tabindex=“0”
tabindex=“0”
tabindex=“0”
tabindex=“0”
tabindex=“0”
tabindex=“0”
tabindex=“0”
tabindex=“0”
tabindex=“0”
Page 106
tabindex=“0”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
Page 107
tabindex=“0”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
Page 108
tabindex=“0”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
Page 109
tabindex=“-1”
tabindex=“0”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
Page 110
tabindex=“-1”
tabindex=“-1”
tabindex=“0”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
Page 111
tabindex=“-1”
tabindex=“-1”
tabindex=“0”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
Page 112
tabindex=“-1”
tabindex=“-1”
tabindex=“0”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
tabindex=“-1”
Page 114
Perceivable
Operable
Understandable
Robust
Page 118
Summary
Perceivable, operable, understandable, robust
Page 119
Summary
Perceivable, operable, understandable, robust
Use standard controls and semantic markup
Page 120
Summary
Perceivable, operable, understandable, robust
Use standard controls and semantic markup
Use ARIA to fill the gaps
Page 121
Summary
Perceivable, operable, understandable, robust
Use standard controls and semantic markup
Use ARIA to fill the gaps
Make sure controls are keyboard accessible
Page 122
More Information
Jake Behrens App Frameworks Evangelist [email protected]
Web Content Accessibility Guidelines http://www.w3.org/WAI/intro/wcag
ARIA Documentation http://www.w3.org/WAI/intro/aria
Combining Web Accessibility and Automation on iOS https://developer.apple.com/videos/wwdc/2011/
Apple Developer Forums http://devforums.apple.com
Page 123
Related Sessions
• Accessibility on OS X Russian Hill Tuesday 2:00 PM
• Accessibility on iOS Russian Hill Tuesday 3:15 PM
• Web Inspector and Modern JavaScript Russian Hill Thursday 10:15 AM