skip-link
Skip link must have a resolvable, usable target
Checks that a "skip to ..." link's href fragment resolves to a real, currently usable element in the document.
Applies to. Applies to <a href="#fragment"> elements that are skip links by one of two signs:
- the accessible name follows a common skip-link wording in one of the shipped locales: "skip" or "jump to" (English); "aller au contenu", "passer au contenu", "accéder au contenu", "accès direct", "évitement" (French); "springen", "überspringen", "direkt zum", "zum Inhalt" (German); "saltar", "ir al contenido" (Spanish); "スキップ", "本文へ" (Japanese). "jump to" sits beside "skip" because real skip links use both conventions (e.g. a "Jump to section" link);
- or it is the first link in the document, and it comes before the
mainelement (or an element whose role attribute resolves to main, its first real role token in any case): the usual place of a skip link whatever its wording.
Other same-page anchor links are not skip links and are left alone. Where the page has no <main> and no role="main", a custom element whose ElementInternals give it the main role (this.attachInternals().role) is the main a link's position is measured against.
Expectation. The link's fragment resolves to a real element in the document (via a matching id, or a legacy <a name="...">), and that target is currently usable (not hidden from the accessibility tree; and, when browser geometry is available, rendered with an area that no ancestor cuts to nothing: one with overflow: hidden collapsed to no size, or overflow: clip keeping it outside). A skip link whose target is missing or effectively unusable does not provide a reliable bypass destination. An empty target (no element or text inside it), such as <a id="content" tabindex="-1"></a> or a legacy <a name>, has no area by nature: following the link moves focus, or the sequential focus navigation starting point, to it (HTML, "scroll to the fragment"), so the next Tab goes on from there. What it marks is measured instead: its nearest ancestor with content of its own, such as the <main> it opens. A display: contents target has no box of its own, and is measured by its children's.
What a finding reports.
href: the link'shref.lean(a finding with a lean): the lean's direction,failorpass, the same as the occurrence'slean.toward, so a standard's mapping, which readsdata.details, can route the finding by it. Absent when the finding has no lean.unusableReasonCode(a target that is not usable): why it is not:ACC_TREE_INELIGIBLEwhen it is hidden from the accessibility tree,NO_CLIENT_RECTSwhen it is not rendered,ZERO_AREA_TARGETwhen it, or for an empty target the content it marks, has no area or is cut to nothing.targetSelector(a target that is not usable): a selector for the target.geometryCheckEnabled(a target that is not usable): whether the target's geometry could be measured, which needs a browser.viewport.width,viewport.height(a target whose geometry was measured): the viewport the page was laid out in, in CSS pixels. A target hidden at one width can be usable at another.
These data.details fields help to read and reproduce a finding. Apart from reasonCode and the few fields Output schema names as stable, they are not a stable contract: a field may be renamed or dropped in a minor release, so don’t build on them.
Examples
<a href="#target">Skip to content</a><div id="target">Target content</div>
The fragment target exists and is usable.
<a href="#missing">Skip to main content</a>
The link's fragment target doesn't exist anywhere on the page, so activating it goes nowhere.
<a href="#contenu">Aller au contenu</a>
French skip-link wording is recognised as well, and the target is missing.
How to check
When this rule can’t decide, it reports cantTell and leaves the question to a person. Each question it can ask is listed here under its reason code, with the steps to answer it. A finding carries the same steps as howToCheck, in the scan’s language. See Output schema.
SKIP_LINK_TARGET_MISSING
- Load the page, press Tab once or twice until the skip link the report names appears, and note its href.
- Press Enter to follow it.
- Press Tab once more and see where focus lands.
Pass. Following the link moves to the main content and the next Tab goes to the first control in it.
Fail. Nothing happens or focus stays at the top, because no element matches the link's target, so the link does not bypass repeated content (best practice, G1).
SKIP_LINK_TARGET_UNUSABLE
- Load the page at the window width the report gives (if any), press Tab until the skip link appears, and press Enter.
- Watch whether the page scrolls to the target and the target area is visible.
- Press Tab once more and see where focus lands.
Pass. The page moves to the visible main content and the next Tab goes to the first control in it.
Fail. The target is hidden, not shown or has no size, so focus does not move past the repeated content (best practice, G1).