Heading levels skipped
What it is
At least one heading on the page is two or more levels deeper than the heading before it, for example an <h4> straight after an <h2>. Headings form the page’s outline: each <h3> is a subsection of the <h2> above it. A skipped level usually means a heading tag was picked for its font size rather than for its place in that outline.
Why it matters
Many screen reader users skim a page by its headings, the way sighted readers scan bold titles. When an <h4> follows an <h2>, they may go looking for a section between the two that does not exist. WCAG does not strictly require levels in order, so on its own this is not a Level A failure, but the W3C’s headings tutorial advises avoiding skipped ranks, and 1.3.1 Info and Relationships (Level A) requires the structure people see to be in the markup.
How Asky checks it
Asky reads the page’s raw HTML and walks the <h1> to <h6> tags in source order; headings added by JavaScript are not seen. A skip is any heading two or more levels deeper than the one before. The first heading may be any level, and going back up is fine. Headings inside aria-hidden="true", hidden, <noscript> or <template>, or with an inline display: none or visibility: hidden style on it or around it, are ignored; headings hidden by a stylesheet still count. One issue per page gives the number of skips and up to 20 examples. The H1 issue non-sequential headings is separate: it fires when the first heading is not an <h1>.
Reported as a warning with low severity.
How to fix it
- Open the examples in the issue. Each shows the level the outline jumped from, the level it jumped to, and the heading’s text.
- Change the deeper heading to the next level down, so an
<h4>after an<h2>becomes an<h3>. Then check the headings after it, which may now skip in turn. - If an
<h4>was used because its size looked right, make it an<h3>and give it the smaller text style. Most site builders let you set a heading’s level and its text style separately. - Text that does not introduce a section, such as a badge, a price or a card label, can be a styled paragraph instead of a heading.
- Do not insert empty or invisible headings to fill a gap; they add noise for screen reader users.
- Fix shared components such as cards, sidebars and footers in their template, so every page that uses them is corrected. Keep the page’s
<h1>as its first heading. - To leave it as it is: if the skip comes from a heading your stylesheet hides from everyone, such as one inside a closed mobile menu, mark the issue resolved.
Example
On https://example.com/pricing, the plan names jump from level 2 to level 4:
<!-- Before: h2 followed by h4 -->
<h2>Pricing plans</h2>
<h4 class="plan-name">Starter</h4>
<!-- After: the correct level, same look -->
<h2>Pricing plans</h2>
<h3 class="plan-name">Starter</h3>