Who it affects
Someone with a motor impairment using a keyboard on a district council website presses Tab 34 times on every page to get past the menu, and the same again after every search.
Someone who is blind using a screen reader has no landmarks or headings to jump to, so has to listen to the menu read out again on each page.
Someone using a switch, one press at a time gives up on a page before reaching the form they came for.
Broken versus fixed
Both examples are live and rendered in a sandboxed frame. The broken one is deliberately broken.
Click inside the frame and press Tab. Ten presses to get past the menu, and there is no heading or main landmark to jump to instead.
Click inside the frame and press Tab once. A Skip to content link appears; Enter moves focus straight to the main content, which also has a heading and a main landmark.
Show the markup behind both examples
<style>body{font-family:system-ui;margin:0;padding:12px}nav a{display:inline-block;margin:0 10px 6px 0;color:#1b5e9e}nav a:focus{outline:3px solid #e07a1f}.content{margin-top:10px;padding-top:10px;border-top:1px solid #ddd}</style>
<nav>
<a href="#home">Home</a><a href="#bins">Bins</a><a href="#council-tax">Council tax</a><a href="#planning">Planning</a><a href="#parking">Parking</a>
<a href="#housing">Housing</a><a href="#schools">Schools</a><a href="#libraries">Libraries</a><a href="#leisure">Leisure</a><a href="#contact">Contact</a>
</nav>
<div class="content">
<p><b>Report a missed bin collection</b></p>
<p>Tell us which bin was missed and we will collect within two working days.</p>
</div>
<style>body{font-family:system-ui;margin:0;padding:12px}nav a{display:inline-block;margin:0 10px 6px 0;color:#1b5e9e}nav a:focus{outline:3px solid #e07a1f}main{margin-top:10px;padding-top:10px;border-top:1px solid #ddd}main:focus{outline:3px solid #e07a1f}.skip{position:absolute;left:-999px;top:8px;background:#fff;padding:8px 12px;border:2px solid #1b5e9e;color:#1b5e9e;font-weight:600}.skip:focus{left:12px;outline:3px solid #e07a1f}</style>
<a href="#main" class="skip">Skip to content</a>
<nav>
<a href="#home">Home</a><a href="#bins">Bins</a><a href="#council-tax">Council tax</a><a href="#planning">Planning</a><a href="#parking">Parking</a>
<a href="#housing">Housing</a><a href="#schools">Schools</a><a href="#libraries">Libraries</a><a href="#leisure">Leisure</a><a href="#contact">Contact</a>
</nav>
<main id="main" tabindex="-1">
<h1 style="font-size:16px;margin:0 0 6px">Report a missed bin collection</h1>
<p style="margin:0">Tell us which bin was missed and we will collect within two working days.</p>
</main>
Test it by hand in two minutes
- Load the page, click in the address bar, then press Tab once. A Skip to content link should appear. Press Enter, then Tab again: focus should now be inside the content, not back in the menu.
- With a screen reader running, open the landmark list (the VoiceOver rotor, or Insert+F7 in NVDA and choose Landmarks). There should be a main landmark.
- Press H in NVDA, or use the VoiceOver rotor's Headings list. The content should start with a heading.
- Check the skip link's target id exists on the page and, if the target is a div, that it has tabindex="-1" so focus really moves.
The fix
<body>
<header><nav>...ten or more links...</nav></header>
<div class="content">...</div>
</body>
<body>
<a href="#main" class="skip">Skip to content</a>
<header><nav>...ten or more links...</nav></header>
<main id="main" tabindex="-1">...</main>
</body>
Put the skip link first in the body. Hide it off screen until it gets focus, never with display:none. Set it once in the page template.
CSS that hides the link until it is focused
.skip { display: none; }
.skip { position: absolute; left: -999px; }
.skip:focus { left: 8px; top: 8px; padding: 8px 12px; background: #fff; outline: 3px solid #1b5e9e; }
display:none takes the link out of the tab order, so nobody can reach it. Moving it off screen keeps it focusable.
Landmarks as well as a skip link
<div class="nav">...</div>
<div class="body">...</div>
<div class="foot">...</div>
<nav>...</nav>
<main>...</main>
<footer>...</footer>
Screen reader users jump between landmarks with one key. The elements cost nothing and need no CSS changes.
Common mistakes
- Hiding the skip link with display:none or visibility:hidden, so it never receives focus.
- Pointing the skip link at an id that does not exist, or at a div with no tabindex, so focus stays where it was.
- Placing the skip link after the logo and menu, where it skips nothing.
- Adding a main landmark but wrapping the header and menu inside it.
WCAG criteria this rule maps to
axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:
- 2.4.1 Bypass Blocks (level A). Official W3C text.
The scanner passes the page if it finds a skip link to an in-page target, a main landmark or a heading. It does not press Tab, so it cannot tell whether the skip link shows up on focus or whether its target really takes focus. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.
Related rules
p-as-heading
A paragraph made bold or bigger looks like a heading to a sighted reader.
A
Hidden elements must not contain anything you can Tab to
aria-hidden-focus
aria-hidden="true" tells screen readers to ignore an element, but it does not stop the Tab key reaching the links and buttons inside.
A
Scrollable areas must be reachable with a keyboard
scrollable-region-focusable
When a box has its own scrollbar, mouse users scroll it with the wheel.