Skip to content

Tutorial

How to build a skip link

In short

A skip link is the first focusable link on the page and points, via an anchor, to the main content's id. Do not hide it with display:none (that makes it unfocusable); move it off-screen and reveal it on :focus. The target needs an id and tabindex="-1" so focus actually lands there.

At a glance

  1. Put the skip link first

    Make the first element in <body> a link with href="#main-content".

  2. Mark the target

    Give the <main> id="main-content" and tabindex="-1".

  3. Reveal on focus

    Hide the link visually (not with display:none) and reveal it on :focus.

  4. Test

    Load the page, press Tab once: the skip link must appear and work.

Every page repeats the same blocks before the real content: logo, main navigation, often a search. Keyboard and screen-reader users would have to tab through all of it on every sub-page. A skip link jumps past those blocks with one keystroke: it is the simplest way to satisfy 2.4.1 (Bypass Blocks).

The problem

Before: not accessibleHTML
<body>
  <!-- Kein Skip-Link: Tastaturnutzer muessen sich durch die ganze
       Navigation tabben, auf jeder Seite neu -->
  <header>
    <nav><!-- 30 Menuepunkte --></nav>
  </header>
  <main>
    <!-- Inhalt -->
  </main>
</body>

/* Oder: ein Skip-Link, der per display:none unfokussierbar ist */
.skip-link { display: none; }

Two variants fail: no skip link at all, or a skip link with display:none. display:none removes the element from the tab order, so it can never receive focus and is useless.

The fix

The link is the first focusable element in the body and points to the main content's id. It only becomes visible on focus.

After: accessible (markup)HTML
<body>
  <a class="skip-link" href="#main-content">Zum Inhalt springen</a>
  <header>
    <nav><!-- 30 Menuepunkte --></nav>
  </header>
  <!-- tabindex="-1" macht das Ziel per Skript/Anker fokussierbar,
       ohne es in die Tab-Reihenfolge aufzunehmen -->
  <main id="main-content" tabindex="-1">
    <!-- Inhalt -->
  </main>
</body>
After: visible on focusCSS
/* Sichtbar erst bei Fokus: aus dem Blickfeld geschoben,
   aber im DOM und in der Tab-Reihenfolge (nicht display:none!) */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  padding: 0.75rem 1rem;
  background: #1d4ed8;
  color: #ffffff;
}
.skip-link:focus {
  left: 0.5rem;
  top: 0.5rem;
  z-index: 1000;
}

Details often missed

  • Do not use left: -9999px alone if the link must support RTL languages: prefer the clip-path or sr-only technique there. For LTR the shown variant is robust.
  • The skip link must have real contrast once visible (1.4.3): white text on blue meets that.
  • A single skip link to the main content satisfies 2.4.1. On very complex pages you may offer more (e.g. "Skip to search").

Test

  1. Reload the page and press Tab exactly once.
  2. The skip link must appear (not stay hidden).
  3. Press Enter: focus must jump into the main content, not just the scroll position.

Frequently asked questions

Why not just display:none for the skip link?
display:none and visibility:hidden remove the element from the tab order. The link can then never receive focus and is ineffective. Use a visual hiding technique that keeps the element in the DOM and focusable.
Does the target really need tabindex="-1"?
Yes, in practice. Without tabindex some browsers move only the scroll, not keyboard focus. tabindex="-1" makes the target focusable via script/anchor without adding it to the normal tab order.
Where should the skip link jump to?
To the start of the main content, usually the <main> element with an id like main-content. That skips the header and navigation.

Request a free scan

Tell us your domain — we run a free initial scan and show you the most important barriers.