Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a11y issues: page nav doesn't trigger assistive tech #5581

Closed
jlengstorf opened this issue May 28, 2018 · 36 comments
Closed

a11y issues: page nav doesn't trigger assistive tech #5581

jlengstorf opened this issue May 28, 2018 · 36 comments
Labels
type: bug An issue or pull request relating to a bug in Gatsby

Comments

@jlengstorf
Copy link
Contributor

Description

Right now, using assistive tech to navigate between pages works, but doesn't announce that the user has reached the next page. This is confusing, so we should find a way to mimic standard navigation behavior when using gatsby-link for navigation.

Thanks to @NickColley for pointing this out! Here were a few suggestions he came up with:

  • Focus the page after routing
  • Use ARIA live regions
  • Use a Service Worker to simulate server routing, but with less lag
    • This seems like the least desirable options, since it would require a full page re-render for all navigation; if someone wants this behavior, they could omit gatsby-link to get it.

Nick has done some research and mentioned he'll follow up on this issue with his findings.

This may be an upstream fix for React Router, but let's make sure it's at least working with a11y in mind in Gatsby.

Steps to reproduce

  1. Visit https://gatsbyjs.org
  2. Start VoiceOver (command + F5)
  3. Use the tab key to focus on a link in the gatsbyjs.org navigation
  4. "Click" the link using control + option + space

It will announce that it is following the link, but will not announce the next page.

Expected result

After navigation, the new page should be announced. For a working example, visit https://smashingmagazine.com, activate VoiceOver, and navigate to the Articles page.

Actual result

After navigation, nothing happens.

Environment

  • Gatsby version (npm list gatsby): V1 & V2
  • Operating System: OS X
@jlengstorf jlengstorf added type: bug An issue or pull request relating to a bug in Gatsby help wanted Issue with a clear description that the community can help with. labels May 28, 2018
@NickColley
Copy link

NickColley commented May 28, 2018

Thanks so much for putting this together!

I'm going to put together the research on the possible options we can go down (that you mentioned).

This will include how they perform when using the most commonly used assistive technologies.

Update:
As far as I know, this is a fairly well documented problem but no projects attempt to fix it by default.

This means it requires pre-existing knowledge of the issue, so the majority of projects are broken.

Ember.js community have a great add-on: https://github.com/ember-a11y/ember-a11y.

While this is not very scientific, if we check how often this is downloaded compared to the ember-cli package, you can see how many people actually opt-in to this.

127 downloads vs 85k downloads
http://www.npmtrends.com/ember-a11y-vs-ember-cli

@ryanditjia
Copy link
Contributor

I believe this issue is related to why Safari reader view—both macOS and iOS—gets stuck to the blog post you were previously on.

Sometimes the reader button doesn’t show up at all, for example when going from /blog/ to /blog/post/, likely because the browser doesn’t fully know the page has changed.

Gif showing the bug:
safari reader mode

@KyleAMathews
Copy link
Contributor

/cc @ryanflorence

@jlengstorf
Copy link
Contributor Author

In #5533, @jhackett1 linked to this article, which offers up an idea for React Router: https://medium.com/@robdel12/single-page-apps-routers-are-broken-255daa310cf

I'd also be curious to hear if any SPA best practices have already been vetted by the a11y pros out there: if you've got time, @marcysutton @LJWatson, I'd love to get your perspective.

@LJWatson
Copy link

Thanks @jlengstorf for the ping.

The trick is to mimic the default behaviour of the browser (and therefore the AT) as closely as possible, and to adopt good practices for authoring content to support this behaviour.

When a conventional page loads in the browser, keyboard focus is returned to the top of the viewport. This enables keyboard users (whether they use an AT or not), to explore the page from the top using whatever techniques they're used to. It also causes screen readers to announce the content of the <title> element - the first indication a blind person has that they've reached their intended destination.

It is good practice to give each page in a website/webapp a unique title that concisely describes the primary purpose of the content. It's also useful if the page title is reflected in an <h1> heading at the start of the main content area.

To make this happen in an SPA you need to fake it: use JS to take keyboard focus to the <body> element (or nearest sensible container) when the view is replaced/updated, replace the <title> element with something unique to the current SPA view, and update the <h1> (assuming it's there) at the start of the main content area accordingly.

jlengstorf added a commit to jlengstorf/gatsby that referenced this issue May 29, 2018
This fix applies focus to the main app div after page navigation,
which triggers screen readers and other assistive tech to announce
the new page. Thanks to @NickColley for initially pointing this
out, and to @LJWatson for jumping in with a fix!

fix gatsbyjs#5581
@jlengstorf
Copy link
Contributor Author

Thanks so much, @LJWatson!

Since Gatsby won't be able to control the <title> or <h1> parts of the app, we'll have to focus on what we can:

  1. Let's add a11y docs to talk about best practices (Add a11y section to the docs #5592)
  2. We can (hopefully) patch gatsby-link to focus on the Gatsby container div after page transitions

I just ran a local test that appears to confirm page navigation works as expected after adding a step that focuses the ___gatsby wrapper after navigation. Will open a PR shortly.

@LJWatson
Copy link

One thing I should have mentioned, is that when a conventional page is loaded and keyboard focus is returned to the top of the viewport, screen readers will automatically announce the <title> element and then start to read the content of the page. When faking it for an SPA, the content of the page may not be automatically read by the screen reader - but this is ok, because focus is in the expected place and the user can explore the content for themselves from this logical starting point. Worth mentioning in case it comes up when you test your fix.

@jlengstorf
Copy link
Contributor Author

Thanks @LJWatson! I was able to confirm with VoiceOver that the fix I'm proposing in #5593 causes the page title to be announced. If you don't mind, once it's merged I'd love to send you a link for confirmation that it's working as you'd expect.

@NickColley
Copy link

NickColley commented May 29, 2018

@LJWatson I had wondered what users do when faced with no update, is it likely any users would consider this a barrier? Would you say your knowledge of the web helps you understand what has happened, or is this something reasonable to expect most users to figure out?

@LJWatson
Copy link

@jlengstorf No problem.

@NickColley
My hunch is that most screen reader users wil think the link (or whatever they activated) is broken, because to all intents and purposes nothing will have happened. Focus will remain on the link and/or be cut loose if the link isn't present in the new view and the page title won't have been announced. Unless they choose to go exploring, people are likely to be oblivious at worst and very confused at best I think. Understanding development certainly helps me figure these things out for sure though!

@KyleAMathews
Copy link
Contributor

Fixed with @reach/router in v2

@marcysutton
Copy link
Contributor

marcysutton commented Feb 26, 2019

I think we need to reopen this, as I'm not hearing page changes announced on my website or gatsbyjs.org now that @reach/router is in place. The resetting of focus to the top of the page works fine, but I don't hear anything announced when I navigate through top-level pages in Voiceover with Safari and Chrome, IE11 and JAWS, or Edge and NVDA. I can open an issue with Reach Router as well, but rather than open a new Gatsby issue I thought I'd keep the discussion here. It seems like we need to do more to communicate to screen reader users here (and hence tweets like this one).

One odd thing with NVDA or JAWS on gatsbyjs.org is when I navigate to /docs, I hear probably the aria-current value for link for some reason, like it's rendering before focus is reset to the top of the page. But it only happens on /docs.

Can someone test a bit with one of the above screen readers as well to make sure I'm not imagining this regression? :)

@marcysutton marcysutton reopened this Feb 26, 2019
@marcysutton
Copy link
Contributor

Update: I'll do some more testing of my own once the CSUN Assistive Tech conference is over, but I'm also doing prototype testing with people with disabilities to try and establish a best practice: https://marcysutton.com/prototype-testing-accessible-clientside-routing/

@NickColley
Copy link

@marcysutton thanks Marcy, let me know if you need any help!

@gatsbot gatsbot bot added the stale? Issue that may be closed soon due to the original author not responding any more. label Apr 4, 2019
@gatsbot
Copy link

gatsbot bot commented Apr 4, 2019

Hiya!

This issue has gone quiet. Spooky quiet. 👻

We get a lot of issues, so we currently close issues after 30 days of inactivity. It’s been at least 20 days since the last update here.

If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!

Thanks for being a part of the Gatsby community! 💪💜

@marcysutton marcysutton removed the stale? Issue that may be closed soon due to the original author not responding any more. label Apr 4, 2019
@marcysutton
Copy link
Contributor

Not stale, just juggling priorities. This is still in progress

@mattcdowning
Copy link
Contributor

@marcysutton Can confirm not hearing page changes announced on MacOS with VoiceOver in Chrome/Safari.

@kencoxdesign
Copy link

kencoxdesign commented Jun 30, 2019

@marcysutton Any update on this? Just finished my first Gatsby site and really don't feel comfortable releasing it with such a huge accessibility hole. Safari/Voiceover is not managing page change focus at all for Links

@marcysutton
Copy link
Contributor

@kencoxdesign yes! I've been conducting user testing on accessible client-side routing for the past month, determining the best way forward to serve people with disabilities beyond screen reader usage only. The latest code development is that we have #13197 to merge, which will make an incremental improvement to at least announce page changes in assistive technology–but we want to improve this even further to handle focus and announcements in a way that better supports keyboard users and screen magnification. So stay tuned for more on that front.

@marcysutton marcysutton reopened this Jul 3, 2019
@marcysutton
Copy link
Contributor

To follow up on this: we are investigating and working on some improvements. Stay tuned.

@marcysutton marcysutton removed the help wanted Issue with a clear description that the community can help with. label Jul 9, 2019
@marcysutton
Copy link
Contributor

Alright folks, here's what I have to report:

This issue isn't actually Gatsby-specific: it stems from @reach/router not providing consistent announcements when a wrapper DIV is focused (Test case in a Codesandbox). The wrapper element currently has role="group" and tabindex="-1", but Voiceover needs an aria-label to expose an accessible name and NVDA wants a different role: "status" and "application" are two working candidates right now, but neither of these solutions are particularly great. I could possibly live with role="status" to get announcements working in NVDA, but there are likely side-effects in Talkback and we'd want to test it thoroughly. role="application" is an absolute no-go as it would sabotage the screen reader experience for all Gatsby sites and isn't worth it in my opinion.

Focusing on a heading in the newly changed content area would be fantastic but it's in the realm of "userland" where we can't control what goes in there. Hence the idea to focus on a wrapper element. It's worth adding that this wrapper focus approach is intended to be a fallback method as more component-driven approach is introduced that provides better functionality and access to a range of users with disabilities. For more on that approach, my blog post is up in PR form now (and open to comments). #15579

@kishba
Copy link

kishba commented Jul 10, 2019

@marcysutton I loved that blog post. It really has me thinking about how a button could be added programmatically to receive focus. I wonder if it would be distracting or too repetitive if the button's label was automatically informed by the first heading within the new content (if one existed)?

@marcysutton
Copy link
Contributor

@kishba that's sort-of what I was thinking–using aria-labelledby pointed to a nearby heading to label it. But we'll need some more testing on that part. Once I've got a solution working I'll circulate it to get some input from users.

@kencoxdesign
Copy link

@marcysutton Great blog post, and I'm glad your testing also caught the aria-current issue. I was already looking into what it would take to add that myself. Would need to add aria-current under the same conditions that the existing css class is added to visually highlight the currently active link.

@PigeardSylvain
Copy link

Is it possible to disabled frontend router to keep a standard way of loading pages ? I think it's the safest way for everyone to access the content.

@NickColley
Copy link

NickColley commented Nov 18, 2019

Client side routers re-implement navigation between pages (views) in the browser.
Assistive technologies rely on this browser behaviour to announce important information such as:

  • when a page has loaded
  • a summary of what can be interacted with (landmarks, headings etc)
  • if a page is taking a while to load it will indicate the progress

It also will:

  • set focus to the document
  • allow for ‘backwards-forwards’ caching of pages
  • allow for streaming the page to the browser before it’s fully rendered

I think that Gatsby should take a step back and review the user needs that led them to making this decision in the first place.

For example, one of the drivers for client side routing is for fast page transitions, this can be achieved with better caching via Service Workers.

This way users can get really quick pages while getting the benefits of full page refreshes that I have listed above.

To quote the author of the client side routing library used in this project:

"There’s a chance I believe client side routing on the web is usually not preferred. Which is ironic.
Might be best for screens where the majority of the UI persists, which is the edge case.
Browsers handle page transitions really well.
Still working through my thoughts 🤔"

Ryan Florence tweet

@PigeardSylvain
Copy link

I agree that the speed of loading is a positive point to work on. However, there are accessibility laws in Europe (and in other countries) that cannot be satisfied by the current functioning and that prevent us from using the product.

@eps1lon
Copy link

eps1lon commented Nov 18, 2019

This way users can get really quick pages while getting the benefits of full page refreshes that I have listed above.

To be honest I personally would prefer standard navigation anyway. Client side routing without a signifier (vanilla routing has this by adding the loading spinner in the tab, client side routing needs transitions) can be confusing ("did something actually happen?").

Wasn't there some research that suggested that some actions can be too fast i.e. users should have to wait a minimal amount of time otherwise they don't recognize that an action happened?

@m-allanson
Copy link
Contributor

See #19290 for our current research into accessible routing in Gatsby.

@madalynrose
Copy link
Contributor

Update:

Our first iteration of accessible client-side routing has been released! Because this issue goes so far back and it's taken us a while to create a deliverable, I'd like to spend some time highlighting the work that went into this improvement, roadblocks that came up during development, and our hopes for future iterations.

With #19290, Gatsby announces routing updates using a live region embedded within our Router. This behavior is confirmed for the following technologies:

  • NVDA + Firefox
  • NVDA + Chrome
  • Safari + VoiceOver
  • Chrome + VoiceOver
  • NVDA + IE11
  • Narrator + Edge
  • Safari + VoiceOver (iOS)
  • Chrome + TalkBack (Android)
    NOTE: Talkback reliably announces each update twice. We were able to minimize bugs in all other testing conditions, but this one seems potentially unfixable. Please let us know if you have a solution.

Work so far

The largest effort in implementing this improvement was in the research phase. @marcysutton has written about her efforts in the comments above, but I'll summarize here as well. Gatsby worked closely with Fable Labs in July 2019 to gather feedback from users with disabilities on a set of prototypes with navigation techniques for JavaScript web apps. You can read more in this blog post, which was updated just recently (January 2020). Based on the July 2019 testing and additional testing done at the Inclusive Design 24 Virtual Conference in October 2019, it was determined that we should:

I was hired in October 2019 to pick up these efforts. Additional constraints applied to this project, as implementing these changes in Gatsby core is different than implementing them in "userland." This was evidenced by differences in behavior between Marcy's prototypes that handled routing themselves and testing sites using Gatsby's core routing.

Once the MVP was created, extensive testing was conducted for as many combinations of free tooling as possible.

Next steps

It's clear that our work is not done here. I want to keep iterating and keep improvin go we can raise the baseline accessibility that each Gatsby site ships with by default.

In order for this issue to not continually expand, we ask that you create new issues for scoped chunks of work (e.g. If you feel especially strongly about Gatsby having an option to turn off client side routing, creating a new issue for that would be fantastic and would help us gauge impact). I'm already creating issues for:

  • Localization of "Navigated to" announcement
  • Adding configuration options for focus and announcements instead of programmatically inferring what should happen on page change (e.g. allowing developers to specify a component or heading that should signify a page change has occurred)

Thank you all for caring so much about this and helping us make the web better for everyone, one incremental improvement at a time. ❤️ 🚀

@NickColley
Copy link

@madalynrose awesome work ❤️ great to see this shipped 👏

madalynrose added a commit that referenced this issue Jan 30, 2020
also add descriptive text for issue #5581
sidharthachatterjee added a commit that referenced this issue Feb 9, 2020
* WIP draft

* rough draft

* Apply stylistic suggestions from code review

Co-Authored-By: LB <barth.laurie@gmail.com>

* add links to issues for upcoming features

also add descriptive text for issue #5581

* update verbiage for a11y nav issue link

* remove unnecessary "/"

* Apply stylistic suggestions from code review

Co-Authored-By: Marcy Sutton <marcy@gatsbyjs.com>

* add skip nav examples

* add PR link

* Apply suggestions from code review

Co-Authored-By: Marcy Sutton <marcy@gatsbyjs.com>

* Fix date

Co-authored-by: LB <laurie@gatsbyjs.com>
Co-authored-by: Marcy Sutton <marcy@gatsbyjs.com>
Co-authored-by: Sidhartha Chatterjee <me@sidharthachatterjee.com>
@Wolfr
Copy link

Wolfr commented Feb 25, 2020

Thanks so much for this work, this is groundbreaking work to make SPAs accessible in general. I can't believe it's only happening just now. We're building a router for Svelte and closely watching this work. If we can contribute back we will.

@marcysutton
Copy link
Contributor

marcysutton commented Apr 24, 2020

Following up here to to ask a specific question of you, @PigeardSylvain, since I'm digging deeper into success criteria for modern, JavaScript web applications. You said:

there are accessibility laws in Europe (and in other countries) that cannot be satisfied by the current functioning and that prevent us from using the product.

Improvements have shipped since then, and I'm familiar with the EU Accessibility Directive and how it relates to WCAG. But I still wanted to ask if there are specific regulations, guidelines, or success criteria that prevented you from using Gatsby, so we can do our best to improve access and compliance. I have some ideas, but in general there aren't currently requirements for user problems related to client-side routing in WCAG. So I'd love to hear more from your perspective (and anyone else with relevant input).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug An issue or pull request relating to a bug in Gatsby
Projects
None yet
Development

Successfully merging a pull request may close this issue.