WWDC2014 Session 516

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Good morning, everyone,
my name is Jesse Bunch.
I'm an engineer on
Apple's Productivity team,
and today I'm going to
be talking to you about
"Improving the Accessibility
and Usability
of Complex Web Applications."
So my teammates and
I have been hard
at work improving the
accessibility of iWork
for iCloud, which is
a sophisticated suite
of web applications designed
to allow you to create
and edit your Pages documents,
your Numbers spreadsheets,
and your Keynote presentations
all across platforms and all
from within your web browser.
While there is still
more work to be done
in making them accessible, we
found that a lot of the issues
that we were fixing in
iWork for iCloud are issues
that are commonplace in
web applications today.
And so we thought it would
be really great to highlight
for you some of these specific
accessibility challenges,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for you some of these specific
accessibility challenges,
as well as provide practical
solutions for these challenges
and give you tips on
how you may be able
to avoid them altogether.
So today, we're going
to cover accessibility
at a fundamental level.
We're going to cover
the latest research
and statistics regarding
users with disabilities.
And then we're going to cover
Web Accessibility Standards
as well as some of
the tools you can use
to help meet those standards.
And then finally, we're
going to apply everything
that we've learned
to help diagnose
and fix some accessibility
issues
in a text editing
application that I've created.
And I'll even show you some
of the new accessibility
debugging tools found
in the Safari Node
Inspector in OS X Yosemite.
So let's get started.
This is the 1992 version
of the very first website.
It's still on the
Internet today.
It's just a page full of
data and links that go
out to other pages
full of data and links.
And it was revolutionary
in its time.
And while it was revolutionary,
it was also very simple.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And while it was revolutionary,
it was also very simple.
In fact, the argument
can be made
that this website was
accessible by default.
After all, it's just text-based
content, and it's rather trivial
to disseminate purely text-based
content to a screen reader.
But if you fast forward
to web applications today,
modern web applications
sometimes use completely
custom controls.
They have real-time
content and data coming
in and out of the page.
They use charts and graphs.
And most of this content
was initially designed
with only the mouse
user in mind.
But what if you don't
prefer using a mouse?
Or what if you can't
use a mouse due
to some dexterity
issue in your hands?
Well, in fact millions of people
every day use accessible web
applications, some of them
with only a single switch
using Switch Control software.
This lady can control an
entire iOS device as well
as your accessible web
applications using only the
single switch that's
mounted by her forehead.
It's absolutely incredible.
And accessibility
is a broad field
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And accessibility
is a broad field
that means different
things to different people.
But in short, accessibility is
about supporting real people
with real needs, whatever
those needs may be.
And sometimes we do that
by providing an alternate
interaction model, such as a
keyboard or a switch control,
that's more appropriate given
the user's specific needs.
And as web engineers, it is our
most basic duty to make sure
that our web applications work
well with assistive technology.
That's true, and we do that by
handling the right JavaScript
events, by adding the
right markup in our code.
But what if we took
it a step further?
What if we designed our
applications so thoughtfully
that they would be useable by
everyone, regardless of whether
or not they had a disability?
The term "universal design"
deals with this specifically,
and the quintessential example
of universal design
is the curb cut.
This is now required by law,
and it's crucial for someone
who needs a wheelchair for
mobility, but it is just
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
who needs a wheelchair for
mobility, but it is just
as useful for someone
who is pushing a stroller
down the street, or
movers moving you
into your new apartment.
Another great example
of universal design
is closed captioning.
Here, we have a baseball game
and the announcer is talking
about this guy's swing -- which
looks beautiful by the way --
and we're using closed
captioning
to provide a text-based
alternative
for the audio track
in this movie.
This is absolutely vital for
someone who is hearing impaired
or deaf, but it is just
as useful in an airport
or a doctor's office or
somewhere else where sound needs
to be regulated and therefore
they may not have audio playing.
For web applications,
a great example
of universal design is
full keyboard access.
This is the idea that your
application should be usable
using only the keyboard.
If we take a look at the Pages
for iCloud user interface,
you'll see that when the user
hits the Tab key, focus is going
to go to the button at
the top of the page.
This is the Zoom popup
button, and you know this
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is the Zoom popup
button, and you know this
because of the blue outline
that appeared over the button.
And I've highlighted
that with that box.
Now, keyboard users
expect to be able
to select a button
using the Space bar
or sometimes the Return key.
So if the user hits the Space
bar to activate this button,
you'll see that the
menu is activated just
as if they had clicked
it with the mouse.
Then we can navigate the menu
with the Arrow keys and go
down to the 75 percent
Zoom level.
And when we get to the
75 percent Zoom level,
a keyboard user expects to be
able to press the Space bar
to activate and select
that menu item.
And so when they do that, you'll
see that the menu goes away,
just as if they had
clicked that with the mouse,
and the Zoom level of the
page obviously changes.
And then you'll notice
an important detail,
that we've set the
keyboard focus back
to the button that
opened the menu.
This small detail is very
important for keyboard users
to be able to save the context
to where they were at prior
to some interactive
element popping up onscreen.
And being able to interact with
the user interface of Pages
for iCloud in this way is
absolutely crucial for someone
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for iCloud in this way is
absolutely crucial for someone
who has a dexterity
issue in their hand
and therefore they
cannot use a mouse.
But it is just as important
for someone who has a lot
of document editing to do in
perhaps a short amount of time
and they want to be as
efficient as possible.
While we're mostly
focused on the human aspect
of accessibility, it
is worth mentioning
that applying the
principals of universal design
and making your web applications
accessible will make them easier
to automate.
And automation has
numerous benefits for you
and your organization.
And for more information about
automation and how it relates
to accessibility, I've included
a link to a previous year's talk
at the end of this presentation.
So as you saw from
the previous examples,
the reasons for making your web
application accessible are not
limited to simply caring
for those with disabilities.
Rather, all users can
benefit from the work
that you do in this area.
But for the purposes of this
talk and our topic of web apps,
we're going to be focusing
specifically on users
with visual impairments
that may or may not be able
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with visual impairments
that may or may not be able
to use our applications
without some sort
of assistive technology,
such as a screen reader
or braille device.
And in fact, that user
base is no small figure:
285 million people across the
world are visually impaired
worldwide, such that they
cannot read some or all
of the given content
of a given web page.
And out of that 285 million
people, 40 million people
across the world
are completely blind
and therefore require the
use of a screen reader
or braille device to
be able to benefit
from your web application.
So for more than 40 million
people around the world,
accessibility is not just
a nice-to-have feature;
it is a vital part
of their lives.
And for some, it is a
prerequisite from being able
to benefit from your application
or the hard work that you
and your teams have put into it.
So now that I've hopefully
sold you on the idea
of making your application
accessible,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
let's talk about some of the
web standards that are out there
to help you along the way.
And specifically, I
want to talk about the
"Web Content Accessibility
Guidelines,"
abbreviated WCAG for short.
Now, the WCAG document is quite
lengthy, but for the purposes
of this talk we can boil it
down to four basic principles,
which are: perceivable,
operable,
understandable, and robust.
And we're going to go
through the four of these
in more detail starting
with perceivable.
Perceivable basically means,
"Do I know it is there?"
In this, we're going back to
the closed captioned example.
In this example we have, you
know, some text-based content
that is an alternative for
the audio track in a movie.
And this is just one example.
In fact, having text-based
descriptions
for non-textual content is one
of the most common accessibility
issues on the web today,
specifically for web
applications because we
like to use buttons
with beautiful icons.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
like to use buttons
with beautiful icons.
And we oftentimes
forget to add the labels
for these buttons
into the markup.
Operable means, "Can I use it?"
This goes back to our full
keyboard access example.
Simply put, if you can navigate
to an element with the mouse
and perform some action on
that element with the mouse,
you should be able to
get to that element
and perform the very same
action using the keyboard alone.
Now, this can be
tricky at times,
especially if you're using
custom controls, but we're going
to discuss a common
approach in the demo later
on that you can take
back and use
in your own web applications.
Understandable should
be fairly obvious:
Does your website's
content make sense?
Does it perform in
predictable ways?
An example of this
would be a segmented
or [inaudible] control, such
as the one found in the Keynote
for iCloud Theme Chooser.
Now, this control might be
perceivable and operable
to a screen reader user, but
unless it's marked up correctly,
the user, when they
land on this control,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the user, when they
land on this control,
might hear something like this.
>> Standard, wide.
>> So voiceover on the Mac
said, "Standard, wide."
That doesn't tell them
all of the information
that a sighted user sees, in
that there are two buttons
on this page, they are
mutually exclusive,
and one of them is selected.
Instead, a better experience
would be to mark up this element
in such a way that the
user hears something
like this instead.
>> Standard, selected tab, one
of two, wide tab two of two.
>> So, again, voiceover said,
"Standard, selected tab,
one of two, wide
tab two of two,"
which tells the user everything
that the sighted user sees
when they look at this control
and is a much better
experience for a voiceover user.
Now, robust is a bit
more complicated,
and we can really divide it
up into two different parts.
The first part of robust
is simply making sure
that your markup is
semantic and correct,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
such that it is displayed
correctly across user agents
and is more resilient to the
change in technology around it.
The second part of robust
is having alternatives
for the presentation
of your content.
So a good example of this
would be iCloud in general,
but let's look at
specifically Pages for iCloud.
If you're editing a document
in Pages and you discover a bug
that prevents you from being
able to access your content,
you could simply open this
document in either the OS X
or the iOS applications and
use the built-in accessibility
support there.
Another great example of
having robust content would be
exporting your data through some
sort of feed, like RSS or Atom.
And this allows the
user to use any number
of accessible applications to
be able to consume your content.
And in other words, no one bug
or issue should completely
prevent users from being able
to access your content.
Now, it's worth mentioning
that having robust content
is not mutually exclusive
with having accessible content.
They are meant to
complement each other
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
They are meant to
complement each other
and give your users options
should they encounter issues.
So as we just saw, your content
should be perceivable, operable,
understandable, and robust.
Now I want to get a bit more
tactical and talk about some
of the ways you actually
accomplish these things,
starting with semantic markup.
So using semantic markup is one
of the first things you can do
to help improve your web
applications' accessibility.
Here are two screenshots
of the very same web page.
The screenshot on the left was
implemented using only div tags
for the headings that
you see on the screen.
The screenshot on the right was
implemented using semantic h1
tags for the headings that
you see on the screen.
Now, to a sighted user, these
two web pages are going to look
and perform in identical ways.
In fact, the sighted user is not
going to be able to know at all
that they were implemented
one way or the other.
But to a user of
assistive technology,
these two pages are going
to appear and they're going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
these two pages are going
to appear and they're going
to perform in completely
different ways.
And to find out why,
let's take a look
at the markup behind the scenes.
As I said, the image on the left
was implemented using only a
div tag.
And, in fact, the style
was actually inlined
in the tag itself.
Now, an assistive
technology user,
specifically a screen reader
user, is going to hear this
when they land on this heading.
>> All about widgets.
>> So voiceover said,
"All about widgets."
And you could argue, "Yeah,
so they got the content
of that heading."
But there's really no
semantic information
that is conveyed here.
And we're especially not
conveying the same information
that a sighted user sees
in that this is a heading.
And in fact it's one of the most
prominent headings on the page.
So this is obviously not the
best experience for the user.
Instead, if we were to
use a semantic h1 tag,
the user using a screen reader
would hear this instead.
>> Heading level 1,
all about widgets.
>> So the voiceover said,
"Heading level 1,
all about widgets."
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
"Heading level 1,
all about widgets."
That conveys way more
information to the user
and is obviously exactly
what the sighted user sees.
So this is a much
better experience.
It's also worth noting
that screen readers
oftentimes allow a user
to navigate the page
heading by heading.
And so using a semantic
h1 tag allows them
to quickly find their content,
especially on long pages.
And so that's also a better
experience for a user.
Now, next up is using
standard controls.
And using standard controls
wherever possible will not only
make the experience better for
users of assistive technology
because the controls
will be more consistent
with what they're used
to on their system,
but it also saves
you a lot of work
in making them usable
and accessible.
Say for instance you wanted
to create a custom slider.
This is the markup that
you might actually use,
and with some CSS magic,
that might be the actual
look of the control.
Now, let's say you wanted
to make this control
work with the mouse.
So you would have to handle
several mouse events in order
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So you would have to handle
several mouse events in order
to make that happen:
mouse down to be able
to start tracking the mouse,
mouse move to update the
control, and mouse end
to finally commit that
value back to the model.
Now let's say you wanted to make
it work with a touch device.
So in that case you would have
to handle similar methods,
except you have this
added complexity
that a touch can be cancelled
if you drag it off of the screen
or up to the browser chrome.
And so you have to
account for that.
You can begin to understand
or think about the kind
of state machine that you're
going to need to be able
to keep track of this control.
Now, so, that's the mouse
and that's touch devices,
but let's say you
wanted to make this work
with the keyboard,
as you should.
So let's scroll everything up
and let's implement
our keyboard methods.
We're going to handle focus
so that we can update the
visual style of the control
when the control gains
keyboard focus to show the user
that they can begin
interacting with it.
Then we have to handle
blur so that we can remove
that visual style when
focus goes elsewhere.
And then we have to handle key
down so that we can respond
to Arrow keys, Home,
and Page Up, Page Down,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to Arrow keys, Home,
and Page Up, Page Down,
all of the different key
combinations that a user
of the keyboard would
expect to be able
to modify the value
of that slider.
This is a lot of work, and you
should avoid it wherever you can
by using standard controls.
The example here would be using
a native input range control,
giving it a minimum
and a maximum value
as well as the current value.
If you do this, the browser
is going to handle everything
for you from mouse events
to touch events, keyboard,
it's going to handle state
tracking, observer notification,
and you're going to get
accessibility out of the box.
So you literally have
to do nothing else
to make this control work if
you just use a standard control.
But you and I both know
that HTML controls can
be difficult to style.
I mean, they're getting better,
but they're still
not quite there.
And so if you couple that fact
with a really great designer
who just handed you a
really beautiful visual spec
for a slider, you're probably
going to have to role your own.
And so let's go back to our
custom slider control and talk
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so let's go back to our
custom slider control and talk
about how you can make
it more accessible.
So this is the markup
that we used,
and we implemented
these JavaScript events.
But you may be surprised to know
that this control is absolutely
inaccessible for someone
who is using a screen
reader or a braille device.
After all, there's nothing in
this markup that tells the user
that this is a slider at all,
much less its current state
with a minimum and maximum value
as well as a current value.
And what's worse is that HTML
doesn't really give us any
ability to be able to tell
the user this information.
So we need something else.
And that's where ARIA comes in.
ARIA stands for Accessible
Rich Internet Applications.
And it was specifically
designed to help bridge this gap
between HTML and
assistive technology
by defining additional
properties that allow us
to describe what an element is
as well as its current state.
So going back to our custom
slider, ARIA allows us
to give this div tag
a role of slider.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to give this div tag
a role of slider.
Now, it's worth mentioning
that ARIA defines
over 50 different
roles that you can give
in many different
situations in your markup,
but for this one we're
going to use slider.
And for any given role,
ARIA also specifies a list
of properties and
attributes that you can use
to describe what the control is
as well as its current state.
So in the case of a slider,
we need to tell the user
about the minimum value and the
maximum value using ARIA Value
Min and ARIA Value
Max, respectively.
We also need to tell the user
what the current value is,
so we'll add ARIA Value Now.
It's worth mentioning that
while we had to handle all
of the JavaScript events
manually, we also have
to handle updating
ARIA Value Now
when the slider's value changes,
so that's yet another thing
that you have to keep track of
if you're using custom controls.
But ARIA has now allowed us to
give the semantic equivalent
of a slider using just a
little bit more markup.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, ARIA is not just for
creating custom controls.
You can also use it to
retrofit old content
without actually
having to gut it.
So going back to our
headings example,
let's say that it was too
risky for you to be able
to change your code to spit out
an h1 tag instead of a div tag.
In that case, we could apply
an ARIA role of Heading as well
as ARIA Level 1 to be able
to give this tag the semantic
equivalent of h1 as far
as assistive technology
is concerned.
Now, obviously for other
reasons, it would be better
for us to use an h1 tag,
but this gives you an option
should that not be possible.
Conversely, let's say that
you were using an h1 tag
and for whatever reason this is
not a heading; it was just used
for styling or whatever
else you might use it for.
ARIA has this idea
of implicit roles.
And so an h1 tag would
automatically get a role
of Heading in an ARIA level
of 1, so you wouldn't need
to specify it in that case.
But if you were using an h1 tag
where you didn't want to convey
that semantic meaning, you could
give it a role of Presentation,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that semantic meaning, you could
give it a role of Presentation,
which would basically strip all
of the semantic information away
from this tag from
assistive technology
and give it the equivalent of
being just a plain div tag.
So that can be useful in time.
Next up is focus management.
Now, ARIA allows you
to mark up your content
to be both perceivable
and understandable,
while keyboard accessibility is
important to making it operable.
But another important aspect of
operability is focus management.
And if you're using
custom controls,
like interactive elements and
menus, you're going to need
to handle the focus
management portion yourself.
And you do that using tabindex.
So HTML's tabindex
property controls,
or basically allows
you to specify
which elements can
gain keyboard focus,
either by the user tabbing
to it with the keyboard
or manually using JavaScript.
And a tabindex of 0 means
that an element is focusable
with JavaScript and it is
in the default tab order.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with JavaScript and it is
in the default tab order.
In other words, a user can
get to it simply by tabbing
to it with the keyboard.
A tabindex of negative 1 means
that an element is focusable
with JavaScript, but it is
not in the default tab order.
In other words, the
user can't get
to it simply by tabbing to it.
And then finally,
leaving tabindex off
of your control will mean
that the element is not going
to get keyboard focus,
either by calling focus on it
with JavaScript or by the user
tabbing to it with the keyboard.
In fact, some older user agents
will actually throw a JavaScript
error if you try to
call focus on an element
that is not focusable.
Now, there's a big asterisk
there because native controls,
like links, and buttons,
and form elements,
all get an implicit
tabindex of 0.
And so you don't need to specify
it for those kinds of controls.
Now, for an example of how
to use tabindex properly
to achieve great
focus management,
let's look at a common
setup in web applications
where you have some focusable
content at the top of the page,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
where you have some focusable
content at the top of the page,
then you have a list of items,
and then you have
some focusable content
at the bottom of the page.
Now, if the user hits
the Tab key on this page,
you can see that focus is
going to go to the link
at the top because,
as you remember,
it has a tabindex of 0.
And the tab order
follows the DOM order.
And so this is the first element
in the DOM with a tabindex of 0.
If they hit the Tab key
again, focus will go
to the link at the bottom.
And this is because none of
the menu items have a tabindex
and they're just plain divs.
Now, let's say you wanted
to make these menu items
accessible with the keyboard.
You could simply
add a tabindex of 0
to each one of these menu items.
But you can imagine if
this menu were quite long,
it would be very frustrating
for the user to have to tab
through each and every
item in the menu to get
to the focusable
content at the bottom.
So a better experience would be
to only expose the currently
selected item in the tab order.
And we do that by giving
every other element a tabindex
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And we do that by giving
every other element a tabindex
of negative 1.
So now the behavior
is like this:
If the user hits the Tab
key, focus is going to go
to the first element in the
DOM that has a tabindex of 0,
then it's going to go to
the next element in the DOM
that has a tabindex of 0.
In this case, it's going to be
the selected item in the list.
And then, if they navigate
this list using the Arrow keys,
you can see that we
are moving tabindex 0
to the currently selected
item each time and making sure
that all of the nonselected
items have a tabindex
of negative 1.
This is called the
Roaming TabIndex Technique.
Now if the user hits the
Tab key, they're going
to leave the list and skip
over all of the elements
with a tabindex of negative
1 and go to the next element
that has a tabindex of
0, which is the link
at the bottom of the page.
This has the added benefit
of saving the user's selected
state, so if they were
to Shift-Tab from this
link at the bottom,
they would go directly back to
the currently selected menu item
in the list, which is a
really great experience
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in the list, which is a
really great experience
for keyboard users.
Now, they only have to hit
Tab twice to get all the way
to the bottom of the page to
find what they're looking for.
So to recap a bit, we've talked
about how content should
be perceivable, operable,
understandable, and robust.
And we talked about how
using semantic markup
and standard controls will
get us most of the way there.
We also talked about how you
can use ARIA to fill the gaps
and make our custom controls
and old content more
accessible and understandable.
And we talked about how to
use proper focus management
and keyboard accessibility
to really clean
up the user experience.
But now we're going to apply all
of that knowledge to diagnose
and fix several accessibility
issues and usability issues
in a text editing application
that I built for this talk.
So here we have a text
editor that I created.
And if you look at it and kind
of click around with the mouse,
you can see that we can zoom.
This is very similar to the
Pages for iCloud user interface
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is very similar to the
Pages for iCloud user interface
that we looked at earlier.
We can also go in here
and we can add text;
we can remove text.
So to a mouse user and to a
visual user, this thing works,
and you wouldn't even know that
it is completely inaccessible.
Now, when you approach an
application and you start
to look at how to make it
accessible, I like to divide it
up into two different parts.
The first part is the
keyboard accessibility part.
Get it working with the keyboard
alone, and then you can turn
on the screen reader and
start looking at some
of the more finer points for
users who cannot see the page.
So, to begin testing
this with the keyboard,
we simply just start hitting the
Tab key and see what happens.
You can see that I'm hitting
the Tab key repeatedly
and you just see that the Safari
Address bar is getting focused.
Nothing on the page
is actually changing.
And that's because none of these
elements are really interactive
and none of them
have a tabindex set.
Because if we look
at the markup,
you can see that the buttons
I have here are just made
with standard div tags.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with standard div tags.
And standard div tags don't
have an implicit tabindex
like interactive elements.
So to get these buttons
working with the keyboard,
we need to just add a tabindex
of 0 to each one of those.
So let me go ahead and just
add that to these buttons.
So you can see that the Zoom
popup button now has a tabindex
of 0.
And the Save button next
to it has a tabindex of 0.
And so now if we save and we
go back to our application
and we refresh, you can see now
that the Zoom popup button has
this blue outline at the top.
And so we know that this
thing has keyboard focus.
But this blue outline
is also applied
when you simply just click
on any of these buttons,
and you can see that
it kind of looks weird.
And so our QA team and our
designers are getting upset
with us because they want us
to remove this blue outline
because it doesn't
look very good.
Well, removing the blue
outline would get us right back
where we started, where these
controls are not accessible
with the keyboard at all because
a keyboard user will never know
that they have focus, and
therefore they'll never know
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that they have focus, and
therefore they'll never know
that they'll be able
to interact with them.
And so a better experience
would be rather
than removing the blue outline,
which is default in the system,
let's style it to make it
look a little bit better.
And so if we jump over to
our CSS, which is right here,
this is the CSS for our popup
button, and let me just add
in a little bit of
code to style that CSS.
So here I've added a focus
selector to the button,
and I'm removing the default
outline with Outline None,
so that gets rid of the blue
outline that they hated.
And then I'm adding border
color to the button itself,
which makes it look
a little bit better.
So if we save that and
we go back to our app
and we hit the Tab
key, you'll see now
that we have this really
beautiful blue outline
on the button.
And our designers and
our QA team is happy,
and our keyboard
users are happy.
So the next thing we want
to start doing is looking
at whether or not we can
actually activate these controls
with the keyboard.
So if I press the Space
bar, I would expect
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So if I press the Space
bar, I would expect
that the menu would come up just
as it did when we clicked it.
And, alas, there is
no menu coming up.
So what we need to do is
we need to actually go back
to the JavaScript and add some
very basic keyboard handlers
to be able to tap into the
same code that gets run
when the user clicks
on it with the mouse.
So let's do that now.
All right.
So we jumped over to our
JavaScript for our popup button.
And I have separated this
code out so that we have kind
of a clean slate for
working with the keyboard.
And I'm going to add some
additional handlers here
that basically just handle
a key down on the button.
And then we check to see whether
or not the event is a key code
of 32 or 13, which is the
Space bar or the Return key.
And then when that happens,
we just call the open method
that is the same
method that is called
when the mouse click
is registered.
And so we're just tapping
into the main code.
We haven't had to really
write anything extra for this.
All right.
So if we save and go back to
the menu, we hit the Tab key
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So if we save and go back to
the menu, we hit the Tab key
and now we want to hit the
Space bar to activate the menu.
And you can see the menu comes
up, so we're getting there.
Next, we should be able
to navigate this menu
with the Arrow keys.
And I'm pressing them
and nothing's happening.
So this is where we're going
to have to write a little bit
of extra code to change
the focus of the menu
as the user uses the Arrow keys.
So let's go back there.
And let's just build
on this right here
and add some additional
keyboard handlers to the menu
for focusing the next
and previous item.
So as you can see here,
we're handling a key down
and we're checking the key code
for a Down Arrow or an Up Arrow.
And when we get a Down Arrow or
an Up Arrow, we're simply going
to focus the next or
the previous item.
And so let's jump over to that
code and see what that does.
So Focus Next Item just gets
the currently focused item.
And if there isn't one
focused it gets the first item.
It calls focus item with the
next item to focus in the list.
And so if we look
at that method,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so if we look
at that method,
you can see that we're setting
the tabindex of negative 1
and then we're just calling
focus on this with JavaScript.
Now, as you can remember
from our talk about tabindex,
calling focus on an element
that is not focusable, i.e., a,
you know, normal div tag,
which doesn't get an
implicit tabindex,
could cause issues
in older clients.
And so we want to be sure
that we have a tabindex set
for this element
before we call focus.
So we're setting
it to negative 1.
And you might be asking,
"Why not set it to 0?"
Well, if we set it to 0,
as the user navigates this
list those elements are going
to be put into the default tab
order, which isn't what we want.
We want the user to be able
to navigate the list
with the Arrow keys.
And then if they were to hit
the Tab key, we want focus
to jump away from the menu to
the next button in the toolbar.
And so that's why we're using
negative 1 here, to keep them
out of the tab order and let
us just focus them manually
with JavaScript.
So if we save that and
jump back to the menu
and then we hit the Space bar.
So now you can see that the
currently selected item is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So now you can see that the
currently selected item is
automatically focused
when we open the menu,
which is a good experience
for our users.
Then we can navigate this
list using the Arrow keys
and then try to select an
element with the Space bar.
And that doesn't work either.
So we need to again go in
and hook into the main code
to select this menu item.
But I wanted to show
you quickly what happens
if we press the Tab
key from here.
If we press the Tab
key, the menu goes away
and focus is returned to
the next item in the menu.
That's why we set
tabindex to negative 1.
All right.
So let's go back to our menu
and let's get this
working with the Space bar.
OK, so all I'm going
to do is go back
up to our switch statement
here that handles our key down,
and we're going to add
additional handlers
for both the Space bar
and the Return key as well
as the Escape key to be
able to close the menu.
OK, so actually we did
not handle the Escape key;
we're going to do that next.
So we've added Space bar
and Return, 32 and 13,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So we've added Space bar
and Return, 32 and 13,
and then all we're doing is
we're selecting the currently
focused item.
So that just gets the
currently focused item
and then it calls the select
code that we have, the same code
that the user uses
with the mouse.
So we can go back to our
menu and refresh the page.
And then as we go to
say 75 percent zoom,
you can hit the Space bar
and see that that works.
But where did keyboard focus go?
The menu went away, but there's
nothing highlighted on the page
and there's no insertion point
in the actual editor itself.
So in this case, we have no
idea where keyboard focus went,
and it probably went to
the body of the page,
which isn't very useful.
So the keyboard user,
if they wanted
to change the Zoom level
again, would have to tab back
to that menu and then
activate it again.
And then, again,
keyboard focus is lost.
As you can remember, it's a
much better experience for us
to focus the element
that opened the menu
after the menu goes away.
And so that's going
to be very simple.
We're just going
to add that code.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We're just going
to add that code.
And then we're going to go in
and when the Escape
key is pressed,
we're going to focus the
button that opened the menu
and then we're going
to close the menu.
Similarly, when Enter
or Return is pressed
and we select the
currently focused item,
we're going to focus the
button that opened the menu
and then close the menu.
So very simple stuff,
but it really improves the
usability for this code.
So going back to Safari,
we go to the menu,
we select 50 percent
and you can see
that the Zoom popup
button is selected now
when the menu goes away.
Really great usability.
And now the user can quickly
change all the zoom levels just
by a couple of keyboard presses.
So that's really nice.
OK, so now we've made this
Zoom popup button completely
accessible, which is really
great for a keyboard user.
But now we want to kind of
switch over and start talking
about screen readers and
making sure that someone
who can't see this page
is able to interact
with these elements correctly.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So the way I'm going to do
that is I'm going to turn
on voiceover and just start
kind of navigating the page
and seeing what I hear.
So I'm going to turn
on voiceover
on your Mac with Command-F5.
>> Voiceover on, Safari editor
window, editor HTML content.
>> OK, so voiceover came
on and told us that we are
on the editor HTML content.
Now, we can kind of navigate
through this page and kind
of see what's going on.
I'm going to quickly jump
over to the Zoom button.
>> Edit interact with canvas,
tool interact 5-0
percent clickable.
>> OK, so we got to the Zoom
button and voiceover said,
"5-0 percent clickable."
Now, that does tell
us what the content is
of that particular
div, and it tells us
that they can do
something with it,
but it doesn't really
give them any information
about what this button is
or really what it does.
We want to instead tell the user
that this is the Zoom popup
button, give its current value,
and let them know that when
they click on this button
or when they activate
this button
that they're going
to get a menu.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that they're going
to get a menu.
And so let's turn off voiceover
and let's go add some ARIA
attributes to this div tag
to convey this information
to the user.
>> Voiceover off.
>> So switching back
to Xcode I'm going
to go back to our markup.
And I'm going to add just a few
ARIA attributes to the markup
to be able to tell the
user a little bit more
about this control.
So as we covered earlier
you can add a role.
And we've added the
role of button.
And then we've also added the
ARIA property haspopup=true.
And what that tells the user is
that when they activate
this button,
a popup menu is going
to come up.
And so they kind of know
that there's something else
that they can interact with.
Similarly, for the Save button,
I've just added a
role of button.
And that's really
all we need to do
because the label is pure
text inside of the div tag.
And so voiceover is going
to get that automatically.
All right.
So if we jump over to
Safari and refresh the page
and we turn on voiceover --
>> Voiceover on.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Voiceover on.
Safari 1-0-0 percent
popup button.
>> OK, so voiceover said,
"1-0-0 percent popup button."
And that's a lot better,
but we're still not
getting the actual --
we're still not telling them
that this is a Zoom
popup button.
So we're going to go add
some ARIA labels to this.
And I'm going to show you how
to add the ARIA label along
with the current
value of the control
to make this control really
usable for a voiceover user.
>> 1-0-0. Voiceover off.
>> OK, so let's add the
ARIA label to the control.
And if we go back into here.
So here is the JavaScript that
actually handles selection.
And so we've added this
method called sync value,
which basically what it does
is when the selection changes
for this menu, it finds out
what the currently selected Zoom
level is.
And then it modifies the markup
to show the current Zoom level.
And we've hooked into that
to also update the ARIA
label attribute here.
And what we're doing is we're
just prepending the value along
with a localized string of Zoom.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with a localized string of Zoom.
And that allows us to tell
the voiceover user a lot more
information about this control.
So flip back over to
Safari, turn on voiceover.
>> Voiceover on 1-0-0
percent Zoom popup button.
>> OK, so that tells the
user everything they need
to know about this control.
Now, if we activate
this control --
>> You are currently
on a popup button.
>> Notice voiceover doesn't tell
us anything about this menu.
>> 5-0 percent Zoom
popup button.
>> But when the menus
value changes,
we do get the updated value.
So the next thing that we want
to do is make this menu more
accessible for voiceover.
>> Voiceover off.
>> So if we flip back
over to the markup,
you can see that the menu is
implemented using only div tags,
which is typically how
you would use a menu.
And so all we want to do is add
some ARIA markup to this menu
to get it usable with voiceover.
So we add it to the menu, a
role of menu, and then for each
of the items we add role of menu
item radio, which tells the user
that they can only select one
of these menu items at a time.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that they can only select one
of these menu items at a time.
You know, you can
use a menu item
if there are multiple
things you can select.
You can use check states,
that kind of thing,
but for this purpose we're only
going to use menu item radio.
And then we're going
to add ARIAchecked=true
for the currently
selected menu item.
And, again, we're
going to update this
as the selection changes.
All right.
So let's jump back to the menu
and see how this changes things.
>> Voiceover on 1-0-0
percent Zoom popup button.
>> So that works out great.
>> One checkmark 1-0-0
percent check, checkmark 1-0-0.
>> Okay. So voiceover
is telling us that we're
on the 100 percent menu
item, that there are 5 items,
and that this one that we're
currently on is selected.
Now, if we navigate
to say 75 percent --
>> 7-5 percent menu, 5 items.
>> Tells us that there
are 5 items in the menu
and that we're on 75 percent.
>> 5-0 percent, one
checkmark, 1-0-0 percent check.
>> OK, great.
>> 7-5 percent, 7-5
percent Zoom popup button.
>> So we've selected 75 percent.
And we just want to go back
into the menu and make sure
that the selection
state was updated.
>> One checkmark
7-5 percent check.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> One checkmark
7-5 percent check.
5-0 percent, 5-0 --
one checkmark 7-5
percent check, check.
>> Great. So this menu is
now completely accessible
with voiceover, which
is really, really great.
OK, so as you saw from the
demo, using just a little bit
of extra HTML markup, tapping
into our existing
JavaScript code
and handling a few keyboard
events, we were able
to really improve
the user experience
of our text editing application.
And we were able to make it
fully accessible using a screen
reader, in this case
voiceover on the Mac.
So to begin wrapping up, I'd
like to re-emphasize four
of the most important
points of this talk.
You should strive to make your
content perceivable, operable,
understandable, and Robust.
Using standard controls
and semantic markup wherever
possible will make this a lot
easier, but you can use
ARIA to fill the gaps
where HTML doesn't
provide you enough control.
And then finally, test your
applications with the keyboard.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And then finally, test your
applications with the keyboard.
All mouse interactions should
be able to be duplicated
with the keyboard alone.
And then fire up a screen reader
and really thoroughly
test your application.
And be asking yourself,
"If I can't see it,
does this really make sense?
Am I really getting all of
the information that's here
that a sighted user sees?"
And then use ARIA to kind
of fill in those gaps
and make your user
experience a lot better.
For more information you
can contact Jake Behrens,
who is our App Frameworks
Evangelist.
I've included links to the
"Web Content Accessibility
Guidelines" as well
as the ARIA documentation
so you can learn all
about roles and properties.
And I've also included the link
to the talk that I promised you
about "Using Accessibility
in Automation."
And of course you can
always reach out to us
through the Apple
Developer Forums.
In case you want a little bit
more information these talks,
I would highly recommend
you check out the videos
of accessibility on OS X iOS.
And then more information
about the "Web Inspector
and Modern JavaScript" can be
found in the talk on Thursday.
Thank you, guys, so
much for listening.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Thank you, guys, so
much for listening.
I hope you have a wonderful
day and safe travels back home.
Thank you.