Implementing an Accessible Skip Navigation Link Requires More Thought Than You’d Think

December 15th, 2016 by zoltan · No Comments

One of the most common and straightforward accessible features of a web site is the “skip navigation” link. These links are intended to make it easier for users with screen readers to skip all the links in a webpage’s header navigation in order to read the content on the rest of the page.

To show an example of one in action, take a look at the video below.

Show the “Skip Navigation” example in action.

Any website that claims to be accessible should implement them, since they are necessary to conform to WCAG Level A. Here are a few organizations that have websites that do:

  • CBC, the national broadcaster of Canada (to non-Canadians, the CBC is to Canada what the BBC is to the UK, except not as well funded).
  •, the online guide to government information and services in the United States
  • Holt Renfrew, a Canadian chain of high-end department stores.
  • The Canadian National Institute for the Blind, a voluntary, non profit rehabilitation agency that provides services for people who are blind, visually impaired and deafblind.

Note in the last example, the skip navigation link is always visible, while the others have it only visible when the user starts tabbing through the document. There is no requirement that the “skip nav” link is hidden by default, but most websites make it this way in order to save on visual real estate.

Let’s show how to implement one of these, step-by-step, explaining along the way the thought into how the end result works.

Note: Although I have called this a “Skip Navigation” link, technically it’s called a “Bypass Block” link, since it can be used to bypass any block of repetitive content on a page. However, I will continue to use the “Skip Navigation” name since it is used commonly on the web.

Code For The “Skip Nav” Link

First, let’s make the markup for the link itself:

  class="visually-hidden visible-when-focused bypass-block-link"
  Skip Navigation

It’s a basic link that links to an id in the document. Note the CSS classes:

  • visually-hidden ensures that the link is hidden on the screen (but perceivable by screenreaders) by default.
  • visible-when-focused will make the link visible when the user uses the keyboard to tab into the link.
  • bypass-block-link will control the look and feel of this link (this class is named after the WCAG guideline, 2.4.1 – Bypass Blocks (Level A)

Here’s what the CSS looks like for these classes:

 * Class for elements that are only visible to the screen reader. From
.visually-hidden {
	clip: rect(1px 1px 1px 1px); /* IE 6/7 */
	clip: rect(1px, 1px, 1px, 1px);
	height: 1px;
	overflow: hidden;
	position: absolute;
	white-space: nowrap;
	width: 1px;
	margin: -1px;

 * For `.visually-hidden` elements that should be visible when it gains focus.
.visible-when-focused:focus {
	clip: auto;
	height: auto;
	overflow: visible;
	position: static;
	white-space: normal;
	width: auto;
	margin: auto;

 * Style for "Skip Navigation" type links.  Should have an href linked to 
 * a `.bypass-block-target` element.
.bypass-block-link {
	position: absolute;
	text-decoration: none;
	background: #ffffcc;
	padding: 0.2em;
	z-index: 10;

The “Skip Nav Target” Code

Now let’s look at the markup for the link’s target:

<main id="main-content" class="bypass-block-target" tabindex="-1">

I used the main tag here, since this is the main content for the page. Most screen readers will report this information to the user, so it is important to do this to tell users that use them that this is the main content.

I also added tabindex="-1" to the element so that the browser knows that although users should not be able to “tab into” this element (like the links on the page), this element should be able to gain focus when it is the target of a link that is clicked (MDN has a lot more information on the tabindex attribute). Adding the tabindex="-1" also:

  • styles the main content when it has focus (which helps partially sighted users know where they are in the document)
  • allows screen readers to automatically read the content to the user when they click on the “skip nav” link.

The bypass-block-target will help us style this element correctly:

 * We don't want the `.bypass-block-target` to have an outline on *just* focus,
 * since this will look strange if regular users click inside this element,
 * since it will look like it was tabbed into
.bypass-block-target:focus {
  outline: none;

 * We do, however, want the `.bypass-block-target` to have an outline when
 * it has focus and it is the target of the document (i.e. the hash tag of the
 * document URL is the same as the "Skip Nav" link).
 * Note that this style is the same as the focus state on all the tabbable 
 * elements.  It doesn't have to be.  WCAG 2.4.7 — Focus Visible (Level AA) 
 * only requires that the focus state is visible, so you can have, say, the 
 * focus state of a button different than that of a form element. 
input:focus {
  outline: solid 2px orange;

In Conclusion

Accessibility (a.k.a. a11y) is an important but historically often overlooked topic in modern web development. A lot of developers don’t think about it because it doesn’t affect them. However, times are changing:

Recently, I have been working on a lot of different sites where accessibility was an absolute requirement. Furthermore, my father has come to depend on a screenreader due to his failing sight, which has opened my eyes (pun intended) to the various accessibility fails that exist on the web today. As a result, I will be writing a lot of accessibility articles on this blog in the future, with focus on not only the cross-browser and cross-device challenges, but also cross assistive technologies (or AT) issues. I will be also improving this blog to ensure it becomes more accessible over time.

Tags: accessibility · , , , , , , , ,

0 responses so far ↓
Give Feedback

Don't be shy! Give feedback and join the discussion.

Please Note: If you are asking for help using the information on this page or if you are reporting a bug with the code featured here, please include a URL that shows the problem you are experiencing along with the browser/version number/operating system combination where the issue manifests itself. Without this information, I may not be able to respond.

An orange star denotes a required field.