#btconf Munich, Germany 15 - 17 Jan 2018

Marcy Sutton

Marcy Sutton works on web accessibility tools for developers at Deque (DQ) Systems, a company focused on digital equality. Marcy is passionate about making the web accessible for everyone, and in 2016 she was given an O’Reilly Web Platform Award for her work in accessibility. She loves applying her skills and personal values on the axe-core project, and co-leading the Seattle Accessibility and Inclusive Design Meetup. She recently started a coding club for Girl Develop It, in her new city of Bellingham, Washington. When away from the keyboard, Marcy can usually be found hiking with her dog, riding a bicycle or snowboarding.

Prefer to watch this video on YouTube directly? This way, please.

Radically Accessible Internet Applications 💯

An accessible internet experience makes all the difference for a person with a disability, whether they're enjoying online entertainment, paying bills or booking a trip to go adaptive skiing. You see, people with disabilities gain privacy and independence when they can handle their own affairs. Wouldn't it be radical if every web application supported users with disabilities?

As web experts, we can enable more of our users by shipping accessible interfaces every time, and I'll show you how. In this talk, We'll audit a web application for accessibility, making the necessary changes to support people with disabilities. The best part about it? By integrating accessibility into our development workflow, we'll make our apps more usable by everyone.

Transcription

Marcy Sutton: Hi, everyone. How are you doing this morning?

Audience: Hey….

Marcy: All right. I think I can get a little more energy out of you, though. How are you doing this morning?

Audience: [Cheers]

Marcy: There we go. Okay, so we are going to start with a video. I’m just going to dive right in. We have audio?

[Loud rock music]

Marcy: Yeah! Look at those splits. How radical is that? They were pretty rad in the ‘80s, skiers doing daffies and really getting after it.

You know who else is really rad? People with disabilities. Veteran amputees, people who are born with disabilities might also want to get after it, get out there. There are ways to adapt to still go out and do your favorite things.

If you’re blind, for example, you can go out with a guide and still get out there and go skiing. I’m super inspired by a friend Haben Girma. She’s deaf/blind, so she can’t see or hear, but Haben is more active than a lot of people I know. She skies. She surfs. She salsa dances. In this video, she is skiing in Utah with a guide, and they are arm-in-arm. Through this body movement, they can make turns. It’s really cool to watch these different adaptations to skiing.

Here’s Haben talking with President Obama on a brail keyboard. That’s how she communicates with people. I just think that’s really awesome that she’s still getting out there and that life goes on if you have a disability. If you’re into that sort of thing, you can still get outside.

But, if Haben or someone else with a disability was trying to book a trip to go skiing or to just get out of town, if she was trying to use a site like Kayak.com--I’m sorry to pick on you if you work there--it was not built with accessibility in mind. You can’t see where you are on the screen if you’re a keyboard user. There’s just a lot of aspects of this user interface that are not designed or developed for accessibility, even though it’s a pretty beautiful interface.

If Haben or someone else with a disability was trying to pay their bills online, they might have a difficult time. Where I pay my power bill at Puget Sound Energy back in the States, they haven’t built for accessibility either. Just because you’re blind doesn’t mean you don’t have to pay your power bill, so that’s a real barrier to someone who has a disability.

If you were going to watch TV, watch some entertainment on Hulu, for example, you might have a bit of trouble. I’m tabbing through the interface, but I can’t see where I am on the screen, which, by the end of the workweek when I can’t physically use a mouse anymore, I need to rely on the keyboard. Their login screen doesn’t trap your focus in there, so you can get stuck behind it. There are lots of problems with this interface that they haven’t considered for accessibility.

In fact, Hulu has been sued, both by the National Association for the Deaf for not having caption content, and a group of blind and visually impaired people have also brought legal action to try and get more audio described content, to try and improve their user interface for people with disabilities.

That’s a bit more of the stick approach. We like to say in accessibility, the carrot versus the stick. I have a beautiful illustration from Michael Whitehead, an illustrator from Australia. This really illustrates that you can poke someone with a stick to try and get them to act on accessibility, a lawsuit, for example, depending on where you live. But, what I like to focus on more is dangling the carrot and doing it for the right reasons because accessibility can be really cool. It doesn’t have to be boring. You don’t have to turn JavaScript off, necessarily. It can be something that we do better at, so let’s talk about how to do that today.

Wouldn’t it be radical if the Web was just more accessible to people with disabilities and they could live more productive, private, independent lives? I have spent my career for the last--I don’t know--seven, eight years working on accessibility. I work on a team at DQ Systems where we focus purely on accessibility, and so I’m going to teach you some of the things that I do to audit Web pages for accessibility and how I use tools to make the Web more accessible.

You can find me on Twitter at @MarcySutton, and my slides are available at MacySutton.GitHub.io/radically-accessible.

Skiing and snowboarding, as Marc mentioned, is really near and dear to my heart. I’ve been doing it forever, since I was a little kid. I love getting out there. I even take my dog, Rainer, and I have a picture of him when we went splitboarding in the backcountry in his really funny snowsuit. It always gets funny reactions.

If I were to have a bike accident or something changed in my life, I know I would want to find a way to adapt and still get out there. That’s true for a lot of people. Not everyone. Not everyone is into that sort of thing, but it’s something I care very deeply about.

I maintain a blog of positive accessibility examples called Accessibility Wins, and I have to be honest with you that it’s really difficult to find good examples, especially in shiny, modern, Web applications built with JavaScript. If you’ve worked on something you’re proud of for accessibility, let me know about it on Twitter or you can submit on Accessibility Wins. I love to give kudos to teams like Expedia. Expedia is doing a way better job at making their travel booking site accessible, and it just helps to lift everyone up and celebrate the wins instead of highlight all the fails, even though there are a lot of them.

I wonder. Why is this so hard? Why is it hard to find good examples? Well, I’ve come to the realization that it starts with how we learn to code. I have an example on the screen from We Bos’s intro to React course that I took. In the first ten minutes, there was an accessibility antipattern. He has a form with an input that doesn’t have a label. For a screen reader user, that’s a critical failure where they might not know how to fill out a form. They might not know they’re being subscribed to spam email. It’s kind of a barrier, a pretty big problem.

When I started as a developer, I didn’t know about this either, so you can learn it, and I’m going to show you how today because I didn’t understand headings. I didn’t know what the button element was for, and I surely didn’t know what Aria was for. That’s an API for accessibility information.

For me, it all changed when I was working at an agency and one of our big clients had been sued for accessibility. In the United States, that’s really common. All of a sudden, my job was to make accessible applications and websites. Through that engagement, I learned so much about accessibility, and I met people with disabilities, which really showed me how much my work mattered to them. I could change lives and make a bigger impact, and that’s why I have never been able to turn that switch off in my mind for accessibility.

I hope that today I can make champions out of all of you; just open that door to accessibility to show you that you can do it. You can start small and iterate. Do it one little thing at a time, and your efforts will be so appreciated by people with disabilities and everyone because inclusive design is really about making things that work for more people.

Today, we’re going to do a bit of live coding. We obviously can’t get to everything in 45 minutes, but I’m going to tell you about some of the common issues I see in modern Web applications because I want more good examples. I think we all in here in the room have the power to make this better, so we’re going to talk about focus management; we’ll do some automated testing for accessibility; we’ll look at the number one issue on the Web for accessibility, which is color contrast; and then a little bit of semantic HTML to make a better screen reader experience.

If you’ve got a computer, which I’m guessing all of you have, you are already equipped to start testing for accessibility with your keyboard. That’s right; the most basic accessibility testing tool is the keyboard, so we’re going to start there. To teach you how I would go about this, I’ve made an app in React, and it has tons of accessibility problems, which was kind of hard for me to make an app with fails in it, but these are things that I see all over the Web. You can find my app on GitHub. It’s called the A11Y DEMO APP, so we are going to get started with a bit of live coding.

But first, I’m going to show you what this app looks like. I’ve made a ski trip organizer, and it has some of the common interface ingredients that I see out there on the Web. It’s got a little side nav that, when we open it, it has items in it. I can close that. It’s got a little booking form thing that looks like something you would see in a train booking ticketing website or to book an airline ticket or something.

I’ve got a little modal window that opens up over the layer, over the site. Yeah. If you’ve written a modal window, you might have some accessibility issues inside if there is a form. It’s a pretty basic little app, but there are lots of opportunities to find issues here.

The first thing I would do if I were debugging a website is just start tabbing through the page. But, unfortunately, I can’t see where I am on the screen. There are some links in here that I am now in this little ski trip form, but I have no idea where I am on the screen. And so, for someone who can’t use a mouse, like me by the end of the workweek, you need to see where you are on the screen.

I’m going to open up the developer tools to see why there is no focus outline. To do that, I’m going to do Alt-Command-i to open the developer tools. We’ll go over to the elements panel. I’ll make that a little bit bigger. Move this up here. Okay, so the first thing I’m going to do is go click on one of these buttons to inspect, and we’ll go look at the CSS for this and figure out what’s happening.

There’s a real button element in my little trip planner thing. It has an icon for pulling up previous trips you may have created. This button is focusable, so that’s a good start, but I can’t see it when I focus. I can even force the focus style in Chrome using this little force element state. It turns out there is a wildcard selector that’s hiding the outline for everyone. This is so unfortunately common because people aren’t a big fan of the focus outline.

But, if I turn that CSS off, hey, I can see where I am on the screen. If I tab around, now it’s giving me much more visual feedback of where I am. Now, you can customize that focus style, but we’re going to go over to our CSS and remove that problematic CSS.

In my text editor, I’ve got some JavaScript because this is a React application. In my CSS, there’s that wildcard selector with outline zero. Get it out of there. Just nuke it from orbit. It’s not doing anyone any favors.

Now, you might have that battle with your design team where they say, “That’s a really ugly outline. I hate it.” There’s a tool. I won’t really go into it today, but there is one that you could use. It relies on a little bit of JavaScript, but it’s called What Input. That allows you to be much more precise with how you apply focus styles and styles depending on your input modality, which means, are you using a mouse; are you using the keyboard? That’s a tip. If you want to go deeper with focus styling rather than just removing it for everyone, that’ll make a much better experience.

If we go back to our JavaScript, I’m going to scroll down here a little bit and just show you how this markup is getting delivered. It’s using JSX, which is a templating, I guess, language in React. So that even if you’re not a JavaScript developer, this is really about what gets rendered in the end. That’s what we want to focus on.

If I go back to our application, I’m going to work on our little navigation item over here. If I tab through the page, I’m not seeing my focus land on this menu, so I can’t actually open it from the keyboard, which is a big problem. Sure enough, there are items in here that I shouldn’t be able to reach. I could see the little status bar down at the bottom of the browser. What’s happening here is my focus is going into this closed menu, and that’s a big problem. Maybe you just shipped a new user interface and you didn’t really consider hiding things that are offscreen.

I’m going to use a tool in our code that you may have heard of called Inert. Inert is an attribute that was in HTML in the spec for a really short time, and then no one really used it, so it got removed. But, we’re currently trying to get it back in because this is such a powerful tool for hiding offscreen content. It’s great for, like, if you have a modal window and you’re seeing what’s behind it, but you shouldn’t be able to interact with it. Inert is a bullion attribute that you can use to make that much easier to hide. It’s currently only available in Chrome behind a flag, but I have some links at the end of my slides for where you can go and vote for it in other browsers.

We’re going to go use Inert in our application. The area that we want to add it to, if I go back to our app, go and inspect this with the developer tools, so we have a little menu. There is an element wrapping everything, and then there is this menu button. Well, guess what. It’s a div. It is not an actual button element. There’s our next barrier that we need to fix. A keyboard or screen reader user wouldn’t be able to get to this menu button, and then they wouldn’t be able to get inside of your navigation.

Let’s go back to our text editor, and we’re going to fix that. Our menu button is coming from this menu.js file. It’s got a lot of internal code to track the state of whether the menu is open or closed in React. Let’s scroll up here. It’s a menu class. This is just the React internals of how this component gets delivered.

The part we want is the actual JSX, so what ends up as HTML? Inside of our menu, we have a close icon and a menu icon. Even the name of that component is a signal that we did something wrong because an icon is just a presentational thing. It’s for display. It’s not a user interface control, as we like to say.

Menu icon is actually coming from a child class. If we go over to this menu icon which, if I was doing this for real, I would rename as menu button, we can go down to the bottom here and see. Oh, yeah, here’s our div. It’s got a click, but it’s not a focusable element, so only a mouse user would be able to use your menu, and that’s not very equal access, is it?

Let’s highlight this div. We’re going to change it to a button. Then, because our menu button just had those three lines for the hamburger button, a screen reader user won’t know what that button is for, even if you make it focusable. We’re going to do, on this button element, we’re going to say “aria-label” and then we’ll say “open menu.” Our menu button, now, you can even see, when I click on it, it gets this focus outline. That means that a keyboard user can focus on it and it says “open menu” so, in a screen reader, that’s much more helpful.

There are a few more things we need to do to this menu. We need to hide the items that are offscreen that we shouldn’t be reaching when it’s closed. When it opens, we need to send focus into this menu. Then when I select an item, say if I change pages and go from homepage to the gear packing list page, I want that menu to slide out of the way and send my focus into the real content. Let’s go do that real quick.

We’ll go back to our menu, and the element that we want, we’re going to use Inert for this. The element we want is one that doesn’t include that menu button but includes just all of the contents. That is this menu wrap element. We’re going to use Inert, which is a bullion attribute. What that means is that its presence is enough. It doesn’t take a value. It’s just, is it inert or not? Is the attribute there or not?

We’re going to trick React into adding this by using the state of our menu. We’ll do this.state.isopen and we’ll use a ternary operator, so if it’s open, we don’t want Inert, so we’re going to pass null or undefined would be fine. This is the little React hacky bit. Or, if it’s closed, we’re going to pass an empty string so that this Inert attribute just ends up in the HTML. That’s what we’re after.

Now our menu, if I tab through the page, I’m not getting onto those items that weren’t supposed to be there. If we go inspect it while it’s open, we can go and see that our menu doesn’t have Inert when it’s closed, which is what we wanted. When I close it, now in here it’s got this little bullion attribute. That’s such a helpful way to hide things that you don’t want a keyboard or really any user to interact with when it’s inactive. The alternative, I can totally illuminate for you that the alternative is really difficult. You have to handle tab index. You have to handle the aria-hidden attribute, and it’s really hairy. We could use your support for Inert. If that would solve a need for you, which I’m guessing it probably will if you’re building user interfaces, it’s really worth it to use a polyfill so you can use this in more browsers. Then give some pressure to browser vendors so that we can all make use of this eventually.

Okay, so we’re hiding things. We need to handle focus, so we’re going to do this the React way by going back to our app.js file. The items in our menu are rendered with React router, so there’s a link component and ends up being a real anchor link, which is what we want because those are focusable. We’re going to use the React technique of using a ref. I’m just going to do the first item to start. We’ll give it a ref of first item. Because this is getting compiled into a React router link component, we’re just using a string for the ref.

When it opens, we’re going to use this isMenuOpen method that’s already hooked into the state of our menu so, when it opens, we’re going to go find that ref and focus on it. We’ll say if.state.isOpen, and I’ll do a little bit of trickery here to get this to work. Ifstate.isOpen, we’re going to use React DOM’s find DOM node to go and get the real element because that’s what we need to focus on. We’re using that ref that we added in our markup. We’ll wait a tick just to make sure that the menu is open all the way, and then we will focus on this first item.

We’re going to do one more thing here before we go and check it in the browser and that’s to handle when we want the menu to get out of the way and we’re going to send focus to the real content. For that, we’re going to actually overload this first item and say, “On click,” and then we will say “this.pagefocus.bind” which is a method we’re about to go define in a second. We’re going to bind it to the current scope, and then we’re going to send it to a ref of main.

We’ve got this div down here with an idea of main, and we’re going to go and add a ref to make it match up with our link. We will say it’s in this ref callback. We’ll get ahold of this node, and we can really call it whatever we want, but we’ve already referred to this.main. We’ll say this.main=node. This is sort of the way that they want you to bind refs in React is to use this callback function.

Now we have a way to bind these two things together, but we need one more item, which is a tab index attribute. Tab index takes different values. If you want to make something focusable like a custom button or something, you should use tab index of zero, but we’re going to use tab index of negative one because we don’t want this element to be added to the tab order. We just want it to catch this focus.

I’m going to hit “save” and we have a problem. Let’s go back up. Oh, we don’t have our page focus. That’s a problem. Let’s go add our page focus method. We have this item. I think we just had a stray parenthesis. There we go. Okay, so now we’ll get this developer tool out of the way.

We can get onto our menu. Our focus is sent into it, so it’s getting a keyboard and a screen reader user into the right spot. They’re not stuck behind it, which would be a problem if you can’t use a mouse. If I go to another page, well, I think we’ve only found the first one. We are now sending our focus into the main content, which is really great. You can sort of script the user’s focus through your application. The more layers and things you have going on, the more important it is to get them into the right spot or else a mouse user might be off in one part of your application and a keyboard user or screen reader user is totally left behind. Focus management is a totally awesome way to make a better user experience for someone with a disability.

We’ve got this focus outline showing on our main element. You could use a focus. I think it’s called Focus Visible now that’s a standards-based way to be more precise with your focus styling or the tool I mentioned earlier called What Input.

I’m going to do one more thing here because, if we don’t have a good semantic structure, we might have a problem in a screen reader figuring out what’s on this page. There are a few different elements on this page. There’s what looks to be a heading. There’s a little form. Then there’s a gallery of images. I’m going to fire up VoiceOver, the screen reader on the Mac, and we’re going to go look at what’s available to us. I’m going to start with the Command-F5.

VoiceOver: VoiceOver on Chrome. Ski trip organizer. Window. My trips. Expand. Select a previous date. Select a later date. Date picker. Type of trip. Go. Gallery.

Marcy: It’s reading out a lot of useful stuff. Depending on how much you have going on, on your page, one way that a screen reader user might navigate is using headings. I’m going to pull up the VoiceOver rotor using Option-Command-U, and we’ll go and look at all the headings on the page.

VoiceOver: View source. Web content. Close tab. My trips. Expand. Form controls menu. You are currently in the--

Marcy: It was actually Control-Option-U, not Option-Command. Once I’m in this rotor, I can actually look around at different things. Right now, it’s showing form controls, and you can see I have a few unlabeled buttons. What does the button do? If you don’t label it, the screen reader user won’t know.

We want to go look at headings. There’s only one heading on this page, and I watched Robin Christopherson, who spoke yesterday. I watched him try to navigate a page the other day. He missed an entire section of a page because it didn’t have a heading. That’s exactly what’s happening here. The only heading on this page is for the gallery. If a screen reader user navigates by headings, which many of them do, they’re going to be completely unaware of major parts of a webpage. What we need to do is go and add a heading. It’s kind of silly that we missed this.

VoiceOver: Headings menu. My trip. VoiceOver off.

Marcy: It’s kind of silly that I missed this, but you can style things to look any way you want. Unfortunately, our ski trip organizer text up here is a div. Yeah, stop me if you’ve heard that before.

What we’re going to do is go into our JSX again, and we’re going to go fix a few things. We’ve got an app header. I can see one problem right here is that we have another div button, so we’ll change that one to a button. We’re just going to fix stuff while we’re in here. Might as well.

Actually, I’m going to wait and do this one a little later. I’m getting ahead of myself. We’ve got a number of items in here. Our main content, it’s a div with an ID of main, and that smells a little funny. I feel like there might be an element for that that might be better.

I’m going to change that right now from a div to a main element. What that will do is, actually, instead of just using a generic div with no accessibility information, this will be a landmark that is just a big signal to a screen reader user that that’s your main content. We have another one right here, a div ID of header. I feel like there might be an element for that as well, a header element.

Right now, we’ve added two landmarks that are much easier. We’ll go and see those in VoiceOver in a minute, but we need to go and find our H1. I believe it is all the way -- where is it? Oh, it’s right in front of my face.

We have a div here with ski trip organizer. We’re going to change that to an H1, and we’ll go back to our app and see what that did for us. Turn on VoiceOver again.

VoiceOver: VoiceOver on Chrome. Ski trip organizer. Window. Has keyboard focus. You are currently on a main in headings menu.

Marcy: Yeah! Look at that. Now we have a heading that says, “Ski Trip Organizer,” which adequately describes what that little widget is. That’s a thing you go and type in your trip that you’re planning, and it’ll tell a screen reader user that that’s the most important thing on this page, this H1.

Maybe it’s further down your page and it doesn’t have a visual heading. You could use some CSS to make it offscreen, and then it’ll still be useful to a screen reader user. But, in this case, our big banner text at the top is the perfect candidate for a heading.

I’m going to go cycle through the rotor. We have Windows spots.

VoiceOver: Images. Menu.

Marcy: Images.

VoiceOver: Text fields. Menu.

Marcy: Text fields.

VoiceOver: Landmarks. Menu.

Marcy: Landmarks. Okay, so we have a couple of landmarks in here, but they’re not labeled. What we should be doing with our landmarks is making sure that they have an Aria label or some other way of exposing the text so that a screen reader user will know what that landmark is for. It might be your global navigation. It might be a navigation for something specific. Using a screen reader like this, like VoiceOver in the rotor, is a really great way to just review what is in your webpage. I really like using this tool for that purpose.

VoiceOver: No items in landmarks menu. Closing landmark. VoiceOver off.

Marcy: One tip is that you have to have to hit Escape to get out of the rotor before you try and turn VoiceOver off.

Okay, so we fixed a number of items using the keyboard. Our focus management is now handled, so that’s in a much better state. But, I’m going to do a bit more testing here using a developer tool that I work on called aXe.

I’ll open the developer tools. I have an extension installed called aXe Coconut, which is a prerelease extension. It has more cutting-edge rules. It supports Shadow DOM, which is a new feature, and so we’re just going to run this extension on the page and see what it finds.

It found a number of items, including missing form labels, color contrast, which I mentioned is the biggest accessibility fail on the Web, and it’s saying that we need content to be in a landmark region. This gives you something to respond to, almost like a checklist.

The regular aXe extension does similar things. I’m going straight for this one because I know it has some cool rules in it. What I’m going to do, we could fix a number of items in this form, but I’m going to go open up our modal window. I’m going to run this again because every time you have a menu, a modal window, or something, you want to run aXe again so that it will test in that content, so let’s run it again.

Ooh! We have a major problem with our modal window. I used the React modal component and, unfortunately, with the default configuration, it adds a huge accessibility barrier. It adds and aria-hidden attribute of true to the body. If you aren’t familiar with aria-hidden, it will strip away all accessibility content, which sometimes is what you want. But, in this case, on the body, that’s a huge problem. aXe Coconut is being very helpful in pointing this out to us that that’s probably not what you want because everything on here is going to be what we call a ghost control.

Let’s go fix our modal, first of all, so we can actually test inside of there. I’m going to go back to my app.js file. In here, I have a handle on the modal. They happen to have made; there’s an API in this component we can use to make this better. We’ll do modal.setAppElement, and we need to pass it a selector, so let’s go back to our app. We’ll go and look at where this modal lives.

The React modal is automatically injected into the DOM. Our app is sitting behind it. It’s got an ID of root, so we want to keep the modal visible, but we want to put that aria-hidden on the actual content behind it. We’re going to go pass that ID to React modal. I can, in a string, say, hash root. Now if we refresh, we can go and open that modal again and see that aria-hidden true is going on at the right place.

I bring this up because this component is happening. It’s doing this right out of the box, and you have to do this extra step, at least in this version, so it’s important to go and see what’s happening with the components that you’re pulling into your app. React modal is doing some things for accessibility, like, it’s handling focus management when you open it. But, it has this major, major problem, and so aXe Coconut helped us identify that problem where otherwise we’d be pouring through the source code to see what’s happening.

Now that that’s not on the body, we can run it again. We can see that aXe Coconut found this form is not labeled. That’s how I was saying a screen reader user might get opted into spam content without realizing it when they’re signing up through a form. If you don’t label things, depending on what browser the user is in or what screen reader they’re using, they might not be able to use your app at all.

Let’s go fix some of those things. If we go over to our little signup form, sure enough, these are all divs again. Surprise! It happens a lot. [Laughter]

We’re just going to go and change each of these to a label element. Because there’s already text inside of there, the label element is wrapping the text of name or email, whatever your field is for. That’s pretty much all we have to do. It’s what we call an implicit label. It’s going to bind that text with the input so a screen reader user will have a much better experience.

If we go refresh, we’ll go open our modal and run this again. We fixed the labeling problem, at least in that case. That’s awesome. That’s really helpful to go and identify these problems.

We still have a bunch of color contrast problems, though. I’m going to show you how I would fix those. I’m going to get out of here; go back to our main page. If we just analyze the visuals of this page, that ski trip organizer text at the top, it’s like a cream color over sort of a lavender. It looks nice, but it’s really hard to see. I don’t know about you, but it’s really hard for me to see, especially if I am out in the sun or I’m on a projector that doesn’t have great contrast.

The barrier that presents is if a user is colorblind or low vision. They might not be able to see the content on your site. Unfortunately, it is very popular to make subtle designs. I’m sure you’re probably familiar with this.

To debug this, I’m going to go back into the developer tools. We’ll go find this text. Using CSS, the text -- shoot, we can have aXe Coconut just tell us where it is. The color contrast here is coming from the primary element, which is a wrapper element. Through the CSS cascade, that’s how our colors are getting applied.

If we go back over there and go to the primary element, there is a new tool in Chrome that I’m going to show you that I love so much because it keeps me right here in the developer tools, and I can pick colors that work a lot better. The primary element, and I have this enabled in Chrome, there’s a color experiment in the developer tools where, when you pull up the color picker, it gives you this contrast line that shows you where your colors are failing.

If I click on here, I can see that the colors I have selected are failing two levels of the Web content accessibility guidelines, both double A and triple A. Those guidelines give you ratios to follow so that your foreground and background colors have enough contrast that someone with a visual impairment or color blindness, however, their brain is processing color, you can pick ratios that are much easier to see. This color picker is pretty awesome because you can just drag the color around, and it’ll update that line.

If I chose something like black, it changes my design slightly, but I can at least pick a color that meets these ratios. I’m just going to go and fix that. Let’s go back over to our code. I’m going to go over to my CSS. I have this color in two places I know that might be not the best, but I’m just going to make it black just to solve this for now. That color picker is just such a great tool for helping you. If you just need to tweak a color, like it’s close but it’s not quite meeting the ratio, this is a great way to just go and get a similar color value that meets those ratios.

Sometimes you might need to go back to your design team and have a discussion about, “Okay. Our brand colors don’t meet color contrast ratios. What are we going to do?” A color picker like this is a great way to explore color values. We can go run aXe Coconut again, and we fixed that one color-contrast problem. That’s pretty cool.

That’s one part of my workflow. This is sort of a manual testing approach. I want to show you how I would do this as a developer to really bake this into our workflow. Say you’re not the only one working on an application. If you have automated tests in your application, guess what. You can test for accessibility there too. Let’s go back over to our application, and I’ll show you some tests that I’ve written.

We were using the aXe Coconut browser extension. The underlying API in that is a JavaScript library that you can use called aXe Core. There is an integration for aXe Core called aXe Web Driver JS. I like this tool because it will open up. You’re using Selenium Web Driver to open a real browser instance just like a user would. aXe Web Driver JS will inject the accessibility API that we’re going to use into the browser, including IFrames.

Vitaly spoke about third-party scripts, and that’s when my ears perked up because we do a lot of work with IFrames. If you think about a user’s experience, they don’t know the contents in an IFrame. They’re just using the site. If there are accessibility barriers in those IFrames, we want to know about it as developers, so we can either change our third-party vendor or we can go back to them and say, “Hey. You need to fix your accessibility problems,” because, depending on where you live, you might have some legal risk. I know in the States we do.

In my tests, we are going to open up a real browser instance. In this case, Chrome. I’m going to go and tell it to go and get the local host, whatever port I’m running my app on. You could have it go to a real webpage out on the Internet. You could have it point to a local host. When it’s done, it’s going to go and close the browser, so we don’t have all these little stray browser instances.

I’m going to go and run aXe Builder on this page and expect that it has no accessibility violations. It’s the same information we were getting in the browser extension but in an automated way instead of a manual testing way. Once we’ve run this, it will return a results object to us that we can assert things on. We can really make use of this. If it has no accessibility violations, at least automated ones, we should be able to assert that there are no accessibility violations.

Then, just like I did in the browser, how I opened up that modal layer, I’m going to do that with code. I’m going to go and find a signup button. I’m going to send the interkey to it to make sure it works from the keyboard, and then we’ll run aXe again. Let’s go back to our command line.

Actually, I think I have it in a different spot. Where is it? Let’s go here. Command line - activate!

Okay, so my app is running in one tab in the terminal because that’s how I often operate with websites. Then I have a fresh tab in my terminal that I’m going to run my test. I’ve used an MPM script in my packaged JSON file. It’s just a script called Integration. I’m going to say, “MPM run Integration,” and tell it to go and run my test.

In the background, I’m going to do that one more time and we can see that browser instance open back there. It’s opening Chrome for us. It’s getting it into the correct state and then asserting that things are happening. We still have things that we need to fix. Let’s go see what it found.

There’s a bunch of stuff in here that we haven’t fixed yet, including the form labels on our homepage. The first thing the user is going to experience, we didn’t fix that yet. That’s a problem. But, it’s telling us all of the data that we could haven’t gotten in the extension, including the color contrast bug I didn’t fix yet, aXe Coconut was skipping over these labels because they were properly hidden when that modal was open. It’s also telling me that I didn’t actually make my modal close button focusable. I think it’s the button to open it. It’s sort of a good technique for making sure that your components work from the keyboard is to try and automate them with the keyboard. Selenium will actually scream at you that it can’t focus the element, which is what a real user would experience, so let’s go fix some of these problems.

The first thing I’m going to fix, because I’m thinking about it right now, is our modal. This signup button, it was saying, even though I’m sending keys to it, it couldn’t fire the interkey because it’s not focusable. Let’s go back to our app, our app.js. We’ve got our modal. Oh, well, there’s another div button in here, so let’s fix that one because we know that’s going to be a problem.

It’s a click event, and it’s a real button, so it’s focusable, but it just has a little X in it. I don’t know about you, but if I was in a screen reader and I landed on a button that just said X, I probably wouldn’t know what that was for, so we’re going to do something similar to our other button that we looked at later. We’re going to add an Aria label and say, “Close modal.” I think it was the open menu one that we looked at earlier, so a similar technique of just replacing that X with some more helpful text, so the Aria label is going to win in this case. We’ve got that one.

Our signup form is the contents of that modal, but we want to go and fix the button that launches this. I think it’s in our header. Yeah, so in our header, up in that top right corner, we’ve got this little button to launch a modal, but it’s a div element. All it has is that little newspaper icon. That’s not very useful, so I’m going to change that to a button element. For this one, we’ll say Aria label. If I can type correctly, we’ll say, “Subscribe to newsletter,” or something like that.

Now, you could argue that an icon button is maybe not enough information. Sometimes this would require going back to your design team and saying, “Hey, these icon buttons are way too vague. Users don’t know what these are for.” Sometimes doing real testing with users is a good way to illuminate if people are getting tripped up by your interface. It might be a sign that it’s intuitive to you as a designer or a developer but not to your real users. But, in the meantime, we can at least make this work from a keyboard and a screen reader user by making it a real button element and giving it a label.

Now, we’ve fixed a few things. We can run our integration tests again and see what’s still failing. Well, yeah, all of our form elements are still having a problem. But, it can actually get into our modal now, so that’s a good start. Since we have a few more minutes, let’s go back to our homepage and go fix some of those label problems. There are a bunch of problems in here. There’s a button that has a title attribute. You might go, “Oh, well, that’s some text it says about my trips.” Now, it depends on what browser or assistive technology the user is in whether that text will actually get exposed.

We could do something similar like Aria label of my trips. I’m just going to remove the title because it’s redundant. Now a screen reader user will know what that’s for. Our label elements have placeholder text, so this is similar to the title attribute where a placeholder is not always exposed. Sometimes VoiceOver will kind of cheat and help you, but that’s not true everywhere. What we would want to do, it’s in a label element, so we could do a few different things.

One thing we could do is add an offscreen span. I’ll say, “Span of class name,” because this is React, so we have to say, “Class name,” to get it to render. Then I have some CSS. Let’s go see. I forget if I have an offscreen. Nope. Visually hidden. Something like that.

You would often have a CSS class that you could use. It would be a utility. Then that’ll let you put stuff offscreen. I don’t actually have it in there, so I’m going to label this right on the input with Aria label. We’ll say, “Name of trip.” You’d want to go through each of your form controls.

If I think back to the rotor in VoiceOver, it was actually showing me some of these, and it would say just “button,” and it wouldn’t say what the button was for. Using either a screen reader or a tool like aXe, you can have it point out all the places that you’re causing problems for a screen reader user. I would go through each one of these. Go and make sure that my tests are passing. That’s how I would walk through an application and make sure it does everything that I expect. That’s what we’re going to do with that for now.

There are obviously more we could do. There’s a bunch of accessibility issues that we could just chip away and iterate over this app and get it into a better state. Those are the major, major problems: not being able to reach things, not having enough contrast, making things that actually work for a screen reader user.

Does anyone remember ski ballet? Can I get a show of hands, ski ballet, anyone? It was ridiculous, right? [Laughter]

Audience: [Laughter]

Marcy: They were doing ski ballet, and it makes my knees hurt just thinking about it. Yeah, no more ski ballet, but I like admiring this because, just to bring it back to ski themed stuff, that was a real thing. I believe it was in the Olympics at one time. [Laughter] A bit of an aside.

What we’ve talked about today, we looked at the Chrome accessibility debugger, including the color picker. You can enable that in the dev tools by opening dev tool settings. There’s a little color inspection thing in there. It’s a really awesome tool. That should land in Chrome Stable here pretty soon.

We talked about Inert, which is part of the Web Incubator Community Group. We really want it in more browsers, so I have some links on the next slide to show you where you can vote for that.

We used the aXe Coconut extension, which is the pre-release version of the aXe extension. It has some more cutting-edge experimental rules. It’s got Shadow DOM support. Those things will eventually move into the full aXe extension. aXe Coconut is only in Chrome because Shadow DOM is only in Chrome, basically. But, there is also a Firefox version of the regular aXe extension.

Then we used aXe Web Driver JS to pull that same accessibility API into our automated test. That’s a really great way to work that into your workflow so that your whole team is onboard and your whole team is finding accessibility problems.

To vote for Inert, I have a couple of links. There are places you can vote in both Edge, Firefox, and Safari. They’re all bit.ly, so bit.ly/inert-edge, bit.ly/inert-firefox, bit.ly/intert-safari. There’s some discussion about whether it might become a CSS property like visibility instead of an HTML attribute, but the general utility will still be the same, and it really solves a harry problem of disabling things for screen reader and keyboard users that you can still see visually. The alternative is messy. It’s a lot of tab index manipulation, some aria-hidden. Inert just makes it so much easier, so go and vote for it.

If you’re new to accessibility, I’ve got some resources for you. There’s a site called DQ University. It’s free to people with disabilities, which is a great resource for learning about accessibility.

I have a course on Egghead.io that you can take that has a lot of these same techniques if you want; something you can kind of pause and watch again. You can go and check those out. I have an article from Smashing Magazine called “Notes on Client Rendered Accessibility,” and it’s all about these sorts of techniques of developing for modern Web applications. Then lastly, the What Input Tool that I mentioned, that’ll keep everybody happy when you’re styling for focus, making sure everyone can reach things, but keeping mouse users happy because--let’s be honest--that is a challenge keeping everyone happy.

With that, let’s go and make the Web more accessible because I know you can make a difference. We all have the collective power in this room, and so hopefully I’ve opened that door and showed you that you can chip away at it and make a big difference.

Thanks so much.

Audience: [Applause]

Speakers