Fronteers Spring conference

Accessibility and Performance by Marcy Sutton

This is the first talk in a set of three talks on Accessible Performance delivered on April 1, 2016 at Fronteers Spring Conference in Amsterdam

How do slow performing JavaScript applications impact user experience for people with disabilities–are there certain aspects of the web rendering process that create barriers when you're relying on a screen reader?

By studying the limitations of browsers with assistive technologies and establishing developer best practices, we can we make faster, more accessible experiences for our users. We'll frame Web Performance with an Accessibility lens, looking at progressive enhancement in detail with server- and client-rendered apps built with Angular 2, React or Ember FastBoot; always remembering our friend, static HTML.

Transcript

But first up is going to be Marcy Sutton, who works at DQ Systems in the states over in Seattle, who also is a core contributor to Angular.

So I'm really interested to hear some thoughts from Marcy to do with accessibility and how that all fits in.

Recently won an O'Reilly Web Platform Award, which is-- wait, where is Marcy.

Which is awesome.

Very happy to see that.

But yeah, here to talk about accessibility and performance, please make her very welcome-- not in a costume, I'll note, but that's no judgment.

She's full of it, it turns out, please welcome Marcy Sutton.

Hello.

Let me get set up here.

Just a second.

OK.

Hello, Fronteers.

You can hear me, OK.

It's time to get going.

Here to talk to you about accessibility and performance.

Something that's a bit of a new topic.

This is a new talk that I've been developing for Fronteers.

So excited to get some feedback and get some new ideas shared today.

You can find me on Twitter at @MarcySutton.

And as Phil mentioned, I'm a senior front-end engineer at DQ Systems.

I work remotely from Seattle.

A bit more about me.

What I'm doing at DQ is working on automated accessibility testing using the Axe-Core framework, which is a JavaScript API you can use in Chrome and Firefox extensions under the Axe name.

And then I'm also working on developer tooling, working accessibility testing into automated unit testing, integration testing using Selenium WebDriver.

So figuring out how we can get accessibility into the development workflow to get it answered sooner than, hey, this is broken, you need to fix it.

So by working it into our developer process, we can have more success.

I also co-started a web accessibility Slack channel with Ryan Florence that can be accessed through Gitter as well thanks to the W3C.

As Phil mentioned, I contribute to Angular.

In Angular 1, I worked on the NG-Aria module.

I've worked on Angular Material, which is the UI framework.

And now I'm starting to contribute more to Angular 2.

I also co-lead the Seattle chapter of Girl Develop It, which is a nonprofit teaching women how to build software.

I'm going to start off with a video of if you're using a screen reader to load a very heavy site, such as CNN, what is that experience like? So let's play this video.

(safari voiceover) Voiceover on safari Favorites window, Toolbar, 78%, 84%, 85%, 88%, 89%, 90%, 90%, 90% loaded.

90%, 90% loaded.

90% loaded.

90% loaded.

You are currently on HTML content.

To enter the web area.

So that is what it sounds like in Safari using voiceover on the Mac.

As the page loads, there's a lot of ads, potentially in iframes.

A lot of content being loaded at once.

And although there is visual feedback, if you can't see and you're using a screen reader, you get this audio feedback which is intended to be helpful to tell you that the page is loading.

And it's only 90% finished.

But the reality of that is that you're waiting for all of the visual assets until the screen reader can then announce what is on the page.

So today we're going to look at what that process is like under the hood and how we can make it a little bit faster.

When I think of performance, I think of the work done by people like Steve Souders, where to graph your performance of a website, you might a waterfall that shows as assets slowed, when they become available.

If we split that process into the back-end and the front-end processes, we can kind of see things that are loaded from the server versus things loaded from the client in the browser.

Mostly, accessibility things relate to the front-end part of this process.

So that's what we're going to focus on when we're looking at accessibility and performance.

Accessibility-- it really is about making web experiences accessible to as many people as possible-- people who can't see or maybe they have color contrast issues, people who can't use a mouse and they need to rely on the keyboard to interact, or even other inputs that we haven't thought of yet.

But those can include screen readers now.

They could use switch controls, all different inputs that people can use to use phones and desktop computers, making sure that everything works for those people.

But getting back to performance and my research for this talk, I kept coming up against this quote, that "you can't optimize what you can't measure."

Well, we've got a bit of problem there with accessibility.

I'll read you this quote from Marco Zehe on why screen reader detection is a bad thing.

Marco says, "letting a website know that you're using a screen reader means running around the web waving a red flag that shouts 'here, I'm visually impaired!' It would take away the one place where blind people can be relatively undetected without their white cane or guide dog, and therefore giving others a chance to treat them like true equals."

So Marco is arguing that he doesn't want his screen reader to be tracked because that's a privacy concern.

So we don't really have a way to track a screen reader.

But we do have this cool API called the Navigation Timing API, where we could break down a network request and things becoming available in your browser in two different pieces.

You could get really deep into this Timing API.

There isn't much for accessibility.

There is this DOM interactive portion.

So at what point does the DOM become interactive, because that's when somebody using a keyboard or a screen reader would finally be able to use the page.

So at least we have that.

But we can't track things like screen readers.

So what do we have for accessibility and performance.

We have known user impacts.

And we'll dive into these a little more.

We have optimizations that we can do to make things faster.

So not just the way that things look, but the way that they actually perform to be faster and be more usable.

And then because I worked on the Angular team and I care a lot about JavaScript apps, I'm going to talk about universal apps and how that technique of loading web pages can provide a lot of value in this space to make things actually usable faster, not just looking like they're loading fast but actually being more usable.

So our first end user impact I want to talk about is interacting with the keyboard.

So if you can't use a mouse, or maybe you're using a keyboard even with your mobile device, if that's the way that you're going to interact with the web page, it's a real bummer when you go to start typing in a text area and it either doesn't respond or you type something and hit Enter and then, poof, it's gone because the web page upgraded and all of a sudden your user input is lost.

So why does this happen? Is it because you're waiting for JavaScript to load and maybe you're on a mobile network with some high latency and things just aren't responding quickly enough for the user? Maybe it's because you're waiting for JavaScript to load.

Maybe it's because in that process the UI thread is blocked so that you can't actually interact with it because there's too much trying to go on.

Does the UI depend on JavaScript for everything? So are you reinventing the wheel and creating components out of divs and aria? I'm not knocking those.

I'm just saying that that's more work that you're pushing into the browser.

So that could potentially slow down the performance process.

I read a really good article recently by Eevee.

It was called "Maybe We Could Tone Down the JavaScript."

I was not the Angular team's-- they were not my biggest fan when I sent this article over to them.

But I thought it was really good.

It was important to look at what users are complaining about.

And this article pointed out that on Twitter, for example, when you're viewing a tweet detail, how many functions on the page rely on JavaScript to happen.

The likes, the pressing the Reply button, which could be an anchor and taking you to another page if you had progressive enhancement techniques happening.

So how much stuff on this page is relying on JavaScript.

And although I think JavaScript is great and you should be able to use it, there may be some fallbacks that we could do using progressive enhancement that would make this not quite so scary.

Another impact, another user impact, is on users with assistive technologies.

So people who are using screen readers, other inputs, that as we saw with the CNN example, the screen reader didn't become ready until the page was ready.

So if you're using a screen reader, what is that impact like? Are you waiting for JavaScript to build the document object model? So with CNN, it just wasn't quite ready until it got to a certain loading progress.

Then all of a sudden, the screenwriter can do its thing.

But why is that taking so long? It is because we're building things with JavaScript? So yeah, what is that loading experience like? And as a side effect of that, and really, what we're going to get into for this part of accessibility and performance is is the accessibility tree slow to update.

That thing that's ready to be announced once the page is loaded, why is that taking so long.

And if you're like, hold on, accessibility what, what is this thing.

The accessibility tree.

It's a thing.

If you didn't know about it before now, now you know.

It is a tree that a browser will create parallel to the DOM.

It's actually a separate structure that gets generated from HTML, CSS, and JavaScript.

What this does is it creates objects that assistive technology can use to announce.

If it's a button, it'll have a button object.

If it has text in it, that text will become part of this tree.

So there's a pretty cool dump of all of this stuff in Chrome.

If you type in (chrome)//accessibility, you can get this raw tree and see what is happening in the accessibility tree.

What I want you to remember is that these objects are created by HTML.

The JavaScript that you load onto your HTML, these things all impact this tree.

So the amount of updating that the tree has to do, it's not just the DOM you have to think about, it's also this parallel structure of the accessibility tree.

So you should consider what you're doing to the DOM may impact this parallel structure.

When does the accessibility tree become available in the rendering flow? I was super curious about this.

And this talk was actually born out of a discussion from some fellow accessibility folks talking about when does the accessibility tree become available.

I have a graphic from this fantastic article called "HTML5 Rocks-- How Browsers Work."

And Tali Garsiel, the author, created some graphics to show each part of the Mozilla Gecko's rendering engine.

They have a WebKit or a Blink version, as well.

But in the Mozilla Gecko version, the accessibility tree becomes roughly available when reflow or layout happens.

So if you're going to optimize things for accessibility and performance a lot of the things you would look at are things that would impact reflow or layout.

So a few examples of those.

If you have display none, that will impact the accessibility tree because it would effectively turn objects on and off.

It's a good technique where sometimes something isn't relevant to accessibility or to a screen reader and you want to hide it completely, you can use display none in CSS, just knowing that it's going to impact this structure.

Could be what you want.

You just want to take care to minimize the number of layout impacting things you're doing right as the page is loading.

Similarly, if you're trying to read an element's computed role or its computed name, those could impact the accessibility tree, as well.

Element.ScrollTop and

other squirrelly things-- if you're trying to do a lot of JavaScript right as the page is loading, these things can obviously impact performance in the DOM and in the browser.

Might not have realized they would impact the accessibility tree.

Window.getComputedStyle, which,

if you've worked in the web, you may have already known that that was an expensive operation to do.

Well, it's even more expensive now that you know that it can impact the accessibility tree, and so on.

There's a lot of these things that this could be a whole research topic on its own.

But there's a great Gist from Paul Irish that lists a lot of these things that impact layout and reflow.

So some optimizations-- we looked at user impacts that obviously a slow performing web page isn't just the way it looks, it's also the way that it actually functions so it can impact keyboard users, it can impact screen reader users.

So how can we make this better? We're going to look at some optimizations.

Now the first one might be a bit counterintuitive to the things that you've Heard often I hear if a custom component has aria on it, which is a set of standard attributes that you can use to expand semantics to custom elements like divs and spans, things they don't have built-in accessibility information, you can use aria for that.

The rule of thumb that I always heard was if it's a dynamic widget, just put all the aria on with JavaScript.

You have your default HTML, and if you're going to be manipulating aria, you can just do with it JavaScript.

It's fine.

What I'm recommending for an optimization for performance is to add default values upfront so that when you're loading HTML from the server, you have all these default values and you're not having to push them over the wire with JavaScript.

Less code to send.

If you're already loading it from the server, you kind of get those free bytes just by including it initially.

So things like rows.

So I have a row of checkbox.

I have aria dash checked to false and tab index of zero to make this span all of a sudden become a keyboard accessible checkbox.

We've heard a few mentions of the critical rendering path so far.

And I want to argue that there's more things that you should be considering.

Now this is a bit challenging because everything can't be first, everything can't be in the critical rendering path.

But I haven't heard very much in the critical rendering path that goes beyond just the way something looks.

So what I'm arguing for is that we should be including keyboard support and accessibility support as early as we can.

So the last optimization we saw, including more data from the initial server render, if we're loading assets that might impact the accessibility or the usability of something, we should be prioritizing some of that JavaScript a little bit earlier, or that CSS.

Consider how the thing is interactive in your critical rendering path.

So prioritizing those actions.

And here's an example.

I was trying to log into Tumblr.

I have a Tumblr blog.

And I was on really slow internet, really slow hotel Wi-Fi.

Could not get the JavaScript downloaded to open a modal window to sign in because the sign in was very heavily scripted.

I could not for the life of me get that particular asset to download before a full page of animated GIF.

So Tumblr-- they're image rich, and that's part of their brand and their experience.

Unfortunately, the functionality of signing in was less important than a full screen GIF.

So I think there's some trade-offs there.

Maybe you need to prioritize getting things to be usable from the keyboard, or even at all.

Another optimization-- use as many browser defaults as possible.

Now how many of you have had a designer come to you and say, I don't like the default select, let's create a custom one.

Yeah.

Have you ever tried to make that accessible because it's really hard.

It's really challenging.

And so if they're also concerned with performance, maybe this is a way that you could push back and say, let's use the default because it's good for performance, it's good for accessibility.

It's worth it to overlook some of those style aesthetics.

So some examples of browser defaults that would give you a win, things like buttons and links because they are accessible by default.

You might want to style them slightly differently, but rather than creating these completely out of divs and then trying to add all of this behavior, if you're using the defaults, you get some wins.

Same thing with HTML5 inputs like text, the things like the date picker are a bit challenging because they aren't fully formed in all browsers.

But if you can use the default, you will get some wins for free.

Focus styles, similarly, if you can battle for that default browser focus ring, you will save yourself some pain.

Because otherwise, you have to throw a lot of JavaScript at it to try and get it to behave the way you want.

And then all of a sudden, you have way more code that you're sending over the wire.

Everything that you customize has to be sent over the wire.

If it's not critical, maybe you can defer loading until later.

Maybe it's not part of the critical rendering path.

But this is something that you need to think about.

OK.

So we've looked at some user impacts.

We've looked at some optimizations.

Now we're going to look at the last subject in here, universal rendering, a.k.a.,

isomorphic JavaScript.

The basic idea is that you're loading the same JavaScript app from the server, so that back-end part of the process.

And then when JavaScript is functional and you've got all your assets loaded, you can upgrade the experience to being more JavaScript heavy.

But the idea is that that initial render happens from the server.

So we've got the render from the server, the browser is loading the full HTML with all of those optimizations that we saw earlier.

And then JavaScript will bootstrap it when all those assets become available.

This starts getting into the land of Frameworks and Hotness and Buzzwords.

So we don't even know what to call it.

Is it isomorphic JavaScript, is it universal? I think universal is the term that's winning, but sometimes-- yeah, we've got a bit of a marketing problem with this idea.

But it's something that people do.

And I think it can provide a lot of value for progressive enhancement because you're building the JavaScript up, any way.

If you could use this technology to expand loading to the server, it would be good for us to go.

It would be good for accessibility.

So I think it's worth looking at.

The first example I'm going to show you-- so we know people are going to do it.

What are some best practices that we could use to actually make this do what we want.

The first example I have is a React Universal blog.

It was in the JavaScript weekly one week as a, hey, check out this tutorial.

So I pulled it up because I was curious.

On the first load, before it gets upgraded with JavaScript, it has a body class of hidden, which comes by way of Bootstrap CSS.

And the default style for that is a display none important.

So if we load it with JavaScript, then it removes that CSS class, and all the content is there.

The problem with this is that by putting this hidden class, all the content is hidden as well.

The accessibility inspector on the iOS simulator, we can see there was no content to show up.

So the effect of loading it from the server but hiding it completely diminishes the point.

When it does load, the content is there.

But we really don't want that to be the best practice.

So don't use the CSS class.

Just let the content load.

Somebody who is doing this very well-- I think they should because they created the term isomorphic JavaScript-- but Airbnb.

One thing that I like that they do really well is enable core functions without JavaScript.

So JavaScript is a thing.

And we love it.

We love the frameworks built with it.

But if you really want to expand support, enabling your core functions at least without JavaScript is a good practice.

So Airbnb, I could search and pull up results because that's their business.

You couldn't search Airbnb and have it pull up nothing.

I think that counts as a core function and something we should be paying attention to.

And then lastly, since I'm running out of time, is something that you should look at if you're using universal JavaScript, is trying to utilize event playback.

So as I mentioned earlier, if you're trying to use a web page and typing into a text area and the app hasn't upgraded yet, when JavaScript finally does upgrade and the app becomes all shiny and fancy and usable, if you type stuff in, you want it to keep track of that and then replay the things that you've typed so that JavaScript can use them.

There's a great library called Preboot.

It's part of Angular Universal.

But I think it was written to be framework agnostic.

And the idea is that it will record and playback your keyboard events so that it can then use that data that you've typed in.

It will also maintain the page focus after it rerenders.

So if you were in a text area typing and it upgrades, it will send you back to the same place.

So this is something I'm keeping my eye on, a place that I want to do some more research as I move forward with this talk.

Because 20 minutes, as it turns out, goes by really fast.

So in conclusion, what I would like you to think about, and I'd admit that you have trade-offs as you're deciding what to prioritize because everything can't be first.

So I want you to think beyond visual performance.

Think beyond the way the thing looks and try to make it usable quicker by pushing less code over the wire in that critical rendering path, optimizing for accessible actions, things where people can use a keyboard and not necessarily a mouse.

And use technology to help more users.

Because that's really the point, right-- making things that people can use.

There's a lot of different kind of people out there, so let's think about using technology to help more users.

Thanks.

[APPLAUSE] Thanks Marcy.

Post a comment