Field Notes

Skip links people actually find

A skip link that is first in the tab order, visible the moment it has focus, and labeled for where it goes. Most skip links fail at least one of those.

  • keyboard
  • navigation
  • css

Press Tab once on this page. A navy box appears in the top left corner that says "Skip to main content." Press Enter and focus jumps past the header and the navigation to the first thing on the page that is not chrome. That is a skip link, and it is the oldest trick in keyboard accessibility.

It is also one of the most often broken. Here is what goes wrong, and what a working one looks like.

Why it exists

A sighted mouse user never reads the header. Their eye lands on the heading and they start there. A keyboard user has to Tab through everything before it: the logo link, six navigation items, a search box, a sign-in button. On every page. A screen reader user hears all of it. The skip link gives them the same shortcut the eye takes for free.

Four ways it fails

It is not first. A skip link after the logo, or after a cookie banner, or in the footer, saves nothing. It has to be the first focusable thing in the document, which means the first element in body.

It is never visible. The classic implementation hides the link with display: none or visibility: hidden so it does not "clutter the design." Both of those remove it from the tab order too. The link exists in the DOM and is reachable by nobody. The corpus page 26-skip-link-hidden is this exact bug.

It is visible only to screen readers. Hiding it off screen with a visually-hidden class keeps it in the tab order, which is better, but a sighted keyboard user presses Tab, nothing visible happens, and they have no idea focus is on a link. It needs to appear when it has focus.

It goes nowhere. The href points at #main but nothing has id="main", or the target is a div that cannot take focus in some browsers, so the page scrolls and focus stays where it was.

The one that works

<body>
  <a class="skip-link" href="#main">Skip to main content</a>
  <header>...</header>
  <main id="main">...</main>
.skip-link {
  position: absolute;
  left: 1rem;
  top: -3.5rem;              /* parked above the viewport */
  background: #0b3d5c;
  color: #fff;
  padding: 0.6rem 1rem;
  border-radius: 10px;
  z-index: 200;
}
.skip-link:focus { top: 1rem; }  /* slides into view on focus */

Four properties, each answering one failure. First child of body. Positioned off screen, not hidden, so it stays in the tab order. Moves into view on :focus. Points at a main element with a matching id, which every browser will focus.

If the page has a search box that is the most common destination, a second link, "Skip to search," is fine. More than two and it becomes the navigation you were trying to skip.

The text matters

"Skip to main content" is the convention, and conventions are what people search for with their ears. "Skip navigation" tells them what they are leaving, not where they are going. "Jump" and "bypass" are fine but less expected. Say where it goes.

Check yours

Reload any page, press Tab once, and look. If you see nothing, the link is missing or hidden. If you see it, press Enter and then Tab again: focus should land inside the main content, not back at the top of the header. The agent ruleset tracks this as AW-KEY-005.

Spotted something this note gets wrong?

Corrections and better examples are the best kind of message.

Send a correction