11ty / 11ty-website

Documentation site for the Eleventy static site generator.
https://www.11ty.dev/
MIT License
473 stars 680 forks source link

Skip link for docs (accessibility improvement) #248

Open M4trox opened 4 years ago

M4trox commented 4 years ago

Is your feature request related to a problem? Please describe. Let's suppose you use a keyboard to navigate through Eleventy docs main page. In order to focus some element within main content (such as link) you have to tab through whole navigation on the left. It takes a while, because there are 57 links in the sidebar!

Describe the solution you'd like Skip link. If you use tab key on the site, you'll be asked to:

Skip link will show up only if tab key used.

Describe alternatives you've considered I have not considered any alternatives ;)

Additional context See how Google does it:

skip-link-in-google

@zachleat if you like the idea, I'll be happy to contribute :)

zachleat commented 4 years ago

Yes, this is very much needed! Moving this to 11ty-website repo.

M4trox commented 4 years ago

Great. I already started to code. Do you think the way the buttons look is fine or do you prefer something in different style?

Zrzut ekranu (753) Zrzut ekranu (754)

zachleat commented 4 years ago

Looks great!

M4trox commented 4 years ago

@zachleat I'm having trouble with choosing the best element to focus on while clicking "skip to main content". Initially, I thought it would be a good idea to focus on whole content section. However, if I wrap content within some div which has tabindex="0" then if someone clicks anywhere within text's body, whole section will focus. It's not natural I'd say - outline around text looks weird.

screenshot-2019-12-09 20_02_01

I realized that each page has title that I can set focus on. But I cannot find where markup for this title (highlighted element) is made? I would like to add tabindex="0" to every heading so I can set focus on it.

mdarrik commented 4 years ago

So you shouldn't need to set tabindex=0 for skip links, instead the recommendation is to set tabindex=-1. This still allows the focus to be moved without causing the problem you discovered. An even better solution is to set and remove the tabindex as the links are interacted with. Here's a solid article that talks about how skiplinks are often broken: https://axesslab.com/skip-links/
The last solution seems to be the most recommended one. Though it does require some JS to get it fully working.

Here's the approach that I'd recommend:

  1. add an id="main-content" and tabindex=-1 to main.
  2. remove the tabindex after the document loads. This lets the skip link work with JS disabled, but isn't a perfect experience.
    document.onload = () => {
    const main = document.getElementById('main-content')
    main.removeAttribute('tabindex');
    }
  3. Define a function to handle link changes. The example in the above article binds to the window and then performs an action on blur + focus. So in vanilla JS, that would look something like this:
    function focusOnElement(el) {
       // set a tabindex = -1 so element can be focused
       element.setAttribute(tabindex, -1)
       element.addEventListener('blur', () => {element.removeAttribute('tabindex')}, {once: true})
       element.addEventListener('focusout', () => {element.removeAttribute('tabindex'), {once: true} } //setEventListener to remove tabindex after focusout
       element.focus()
    }
    window.onhashchange = () => {
       const targetElement =  document.getElementById(window.location.hash.replace(/#/, '')) // removes the hash from the id
       if(targetElement) {
          focusOnElement(targetElement) 
       }
    }
mdarrik commented 4 years ago

So based on some more recent testing. The iOS bug referenced in the article above is no longer valid. But, in the name of progressive enhancement (older iPhones, and anyone using older versions of Chrome or Internet Explorer), I'd still recommend a similar approach to above.

This means that while you still need an id on main, you no longer need the tabindex=-1 initially. This also means you can skip step 2 entirely. There's an added bonus that this will improve the experience for mouse users who may have JS disabled while visiting the docs.