Heading-level skips (#436)¶
Why there is no screenshot¶
Nothing moves. The fix keeps every heading's visual size by moving it to a .h5 / .h6 class and changes only the tag — so a pixel diff is the proof of correctness, not the finding. What changed is the document outline, which is what a screen-reader user navigates by and what a camera cannot see.
Measured across a 415-page build¶
| before | after | |
|---|---|---|
| pages with at least one level skip | 391 | 66 |
| total skips | 1,060 | 173 |
metrics.json carries the per-source breakdown for both builds.
The two that mattered most were not the ones the issue named first¶
The issue's evidence led with the cookie modal. That was right, but the aggregate says the damage was concentrated in two pieces of site-wide chrome, each hitting all 391 affected pages:
| source | skips | pages |
|---|---|---|
cookie modal — h2 title, h6 categories |
391 | 391 |
settings offcanvas + language panel — h2 title, h6 section labels |
391 | 391 |
| author card under "About the Author" | 72 | 72 |
| related-posts card titles | 55 | 55 |
The language panel was not in the report. It ships on every page for the same reason the cookie modal does, and it was doing exactly the same thing.
A real article outline¶
before: h6 'Language' <- SKIP from h2
h2 'About the Author'
h5 'Zer0-Mistakes Team' <- SKIP
h3 'Related Posts'
h6 'Docker for Jekyll…' <- SKIP
h2 'Cookie Preferences'
h6 'Essential Cookies' <- SKIP
after: h3 'Language'
h2 'About the Author'
h3 'Zer0-Mistakes Team'
h2 'Related Posts'
h2 'Cookie Preferences'
h3 'Essential Cookies'
A second mistake, caught by the first being fixed¶
heading-outline.spec.js originally scoped its offcanvas cases to #infoSection. The offcanvas is #info-section; #infoSection is its <h2>'s id, used by aria-labelledby. The region locator matched nothing, so test.skip(count === 0) skipped all three cases silently — CI printed them as -, not as failures, and I read the suite as passing.
Correcting the selector made them run, and they failed on a real skip I had missed:
That heading is injected at runtime by assets/js/modules/theme/appearance.js. No grep over _includes/ or _layouts/ can find it — only a rendered assertion can. The same file already emitted <h3 class="h6"> in its other branch, so the fix makes the two consistent.
Skips are not passes. A locator typo is indistinguishable from "this region isn't on this page" unless you look at the counts.
The mistake worth recording¶
The first pass changed the six h6 section labels in info-section.html and rebuilt. Total skips went UP, 1,060 → 1,072. Two sibling components — background-settings.html and admin-links.html — render into the same offcanvas with the same class pattern but live in separate files, so a per-file replace missed them. Moving their neighbours to h3 turned those two into new h3 → h6 skips.
A source-level review would have called the first pass done. The build is what caught it.
Why one component takes a parameter¶
author-card.html renders under an h2 in author-bio.html and under different ancestors in eleven other call sites. No single hardcoded level is correct for all of them, and picking h5 for its font-size is what produced the original skip. Its level is now include.heading_level, defaulting to the historic 5 so every caller that does not say keeps its current behaviour; author-bio.html passes 3.
What is deliberately still broken¶
66 pages still carry 173 skips, concentrated in news/index.html and the section index layouts (inline card markup, not a shared component) and in page content that jumps h1 → h3. That is a second pass over different code, not a finishing touch on this one.
This is also why heading-outline.spec.js asserts on the chrome regions rather than whole pages. A site-wide assertion is the right eventual test; adding it now would ship a test that fails on its own branch.
Tests, both directions¶
test/visual/core/heading-outline.spec.js, run against two served builds: