Recently CSS Tricks posted "A Deep Dive on Skipping to Content" by Paul Ratcliffe. It's great to see so much content lately focused on accessibility, and this article should prove useful for many years to come.
However, I've got a few thoughts on the implementation which I think can improve it a bit, related to the skip link target element. I posted some of these as a comment on the article, but I thought it worth writing up in a blog post as well. Keep in mind, these are relatively minor quibbles. The main thing is that your site has a skip link, and that it works; and if you follow the advice in the article you'll be miles ahead of sites that don't.
The target element
The article's recommended implementation uses an <a>
as its target. This is, as far as I understand, an outdated method for jump links, as it requires an extra non-semantic element just to provide the target. More typically these days the target is an element with an ID, which is how I implement skip links. Up till now I have usually put the target ID on the page's <main>
region (this is also WebAIM's recommendation).
However, after discussing this with my boss, an accessibility expert, he had a slightly better suggestion, which I'll describe in the conclusion (jump to the conclusion).
The article says:
We link to an anchor (
<a>
) element rather than adding the id attribute directly to the<main>
element for two reasons. First, it avoids any issues with the keyboard focus not moving correctly (which can be a problem in some browsers); secondly, it means we can provide clear feedback to the user to show that the skip link worked.
This is, I think, a bit of a misunderstanding. Keyboard focus not moving correctly in some browsers is also an issue with links as jump targets. Modern browsers normally focus the target, whether that's an <a>
element, a <div>
, or whatever; but some older browsers don't. I have a bit of JavaScript I add to my sites to fix this. (You don't want to use this as-is if you have targets which are also links, e.g. in footnotes, as giving them a negative tabindex value takes them out of the keyboard focus order).
const jumpLinks = document.querySelectorAll('a[href*="#"]');
jumpLinks.forEach(function(link) {
link.addEventListener('click', function() {
const href = link.href.split('#')[1];
const target = document.getElementById(href);
if (target) {
target.setAttribute('tabindex', '-1');
target.focus();
}
});
});
The target link is in the normal focus order of the page
This apparent misunderstanding is I think why the author gives the target link an <href>
attribute. Normally jump link targets have only IDs, not <href>
s, except when you want the user to be able to jump back and forth between the target and another link, as with e.g. footnotes.
Giving the target link an <href>
puts it in the native focus order of the document, meaning that keyboard users tabbing through the page will also focus it. The author treats it like the skip link — visually hiding it until it receives focus. But it will not only receive focus when the skip link is activated, but every time the keyboard reaches it – although it provides no useful function in that context.
Visual feedback for sighted keyboard users
I am unclear on what the author means by "it means we can provide clear feedback to the user to show that the skip link worked." In his reply to my comment, he clarified that he was referring to sighted keyboard users. However, when a jump link target is focused, the page scrolls to the target, placing it at the top of the document window. This provides adequate visual feedback of what has happened. In addition, tabbing will focus the first focusable element in or following the main region, additional feedback that the virtual cursor has moved.
If you focus the page Heading 1 (as I discuss in the conclusion), you can give it a focus outline for additional visual feedback.
Target link has extraneous text label
The text label the author gives it is "Start of main content." which is information that is already visually available to sighted users, and programmatically available to non-sighted users (if you've provided a <main>
region).
A crucial concept in accessibility is that you don't want to litter your code with extra "help" for assistive tech users (except where it really is necessary); whenever possible you want to simply allow semantic, well-crafted HTML, text labels, etc, to do their job. The goal is an equivalent experience, not a special experience for AT users; too much "helpful" ARIA or extra text is more burdensome for SR users than useful.
The target is a link to itself
The <href>
value of the link is its own ID, making it a link to itself. This has serious potential for confusion, particularly for non-sighted users. They activate the skip link, only to be taken to something that announces itself as "Start of main content, link" (NVDA). This sounds like a link that will take the user to the start of the main content, but they've just followed the skip link promising to take them there.
Activating it, of course, takes the user nowhere, even more confusingly.
The target is outside the main region, though it announces itself as being the start of the main content
The article implementation places the skip link target outside the <main>
region. The author mentioned in a reply to my comment that he thought putting it inside could have SEO implications, which I doubt but can't comment on. However, not having a text label for the link, or linking to the <main>
region itself, would remove that concern.
This placement is misleading for non-sighted users, who are told they're at the start of the main content but really aren't. This might seem like a minor quibble given that arrowing or tabbing forward will take them immediately into the main region; however, it has the potential for confusion.
Putting the link inside the <main>
means that a screen reader will announce the main region when it is focused, providing the same information as the link label but with native semantics rather than extraneous text.
For instance, NVDA speaks it as "Main landmark, start of main content" (with the author's suggested label). If you don't give it a label, screen readers will typically read the <href>
value (if it has one); NVDA reads it as "clickable" if it has no text label and no <href>
. You can give it aria-hidden="true"
to keep it from being announced at all.
Conclusion
As mentioned, up till now I've usually made the <main>
region the skip link target. However, my boss had a better suggestion when I discussed this with him, which is focusing the page Heading 1 (normally this should be the first element inside the main content).
Why? When you focus a container, screen readers start reading out all the text inside it and don't stop until the user manually stops it. As an analogy for sighted users, think about if following the skip link made the page start automatically continuously scrolling, and you'd have to figure out a way to make it stop and scroll back to where you were.
Focusing a text node means the screen reader reads only that node and stops, allowing the user to navigate forward at their own pace.
So I'd say it's probably best to focus either the page title (assuming it's the first element inside the main region), or a target link. Either way, the screen reader will announce the main landmark if the target is inside it. If you use a link, don't give it an <href>
or text content, do aria-hide it, and put it inside the <main>
region. Use my JS snippet to cover focus management in older browsers, whichever element you use. (Be sure never to give the heading or any other non-natively-focusable element a tabindex value of 0 or higher, as this makes them mouse- and keyboard-focusable).
Again, these are minor quibbles intended to make an accessible implementation even better; the main thing is the author of this article cares about accessibility enough to make the effort, and even straightforwardly implementing his recommendations will give you basically adequate skip link implementation.
Comments
Visual feedback for sighted keyboard users = people like me. I cannot use a mouse, so often use a keyboard to get around a web page (when on a desktop computer, at least). The Tab key being the most common navigation method. Having skip links (and indeed any fragment link) not move the keyboard focus, just the viewport, in extremely frustrating. I worked with Paul a billion years ago (the early noughties!) on his original skip link, which is probably why he still keeps that use case in mind. It’s not that unusual a user type — people with bad RSI would fall into the same group. Accessibility isn’t just for the folks with impaired vision, you know.
Also on a separate note, don’t forget that there are plenty of people with low vision who may be using assistive tech such as Voiceover but also want visual feedback *and* a focus movement.
Thanks for your feedback! I think we are agreeing - my recommendations are focused on making sure keyboard focus moves to the main content. As for visual feedback, my post says "If you focus the page Heading 1 (as I discuss in the conclusion), you can give it a focus outline for additional visual feedback." Perhaps that should be a stronger recommendation to add a focus indicator. Appreciate your lived experience input.