chrome devtools的accessibility面板可验证html大纲合法性:首屏必须有h1,heading-level须从1开始且连续,多h1会导致结构失效;inspect aria attributes能快速查看不受样式影响的aria-level;section作为sectioning root可重置层级计数,而div等非语义容器无法重置。

直接用浏览器的 Chrome DevTools 就能完成,不需要额外引入解析引擎——现代浏览器内置的 Accessibility Tree 就是标准 HTML 大纲解析器,它严格按 W3C Outline Algorithm 执行,比任何第三方库都权威。
Chrome DevTools 中怎么看 heading-level 是否合法
打开 DevTools → 切换到 Accessibility 面板 → 右键任意 <h1></h1>~<h6></h6> 元素 → 选 Reveal in Accessibility Tree。重点看右侧显示的 heading-level 值:
- 是否从
1开始?首屏 DOM 必须有h1,JS 后续插入的不算(爬虫和部分读屏器看不到) - 是否连续?
h1后接h4会显示heading-level: 4,但中间缺2和3,这就是跳级,Accessibility 面板会标红 - 同一页面是否出现两个
heading-level: 1?多h1会导致大纲分裂,不是警告,是结构失效
为什么 inspect ARIA attributes 比看 Elements 更快
右键标题 → Inspect ARIA attributes 能立刻弹出浮层,显示 aria-level,这个值和 Accessibility Tree 中的 heading-level 一致,且无需切换面板。它绕过了渲染样式干扰,直击语义解析结果:
-
aria-level是浏览器对标题层级的最终裁定,不受 CSSfont-size或display: none影响 - 若某
h3被包裹在<div> 里而非 <code><section></section>,aria-level可能突变为4或5,说明结构被误判 - 富文本字段输出的
<p></p> <h3>xxx</h3>会导致aria-level为0或缺失——浏览器直接忽略该标题 - 数值强制截断:
const level = Math.min(6, Math.max(1, parseInt(props.level) || 2)) - 禁止传入字符串
"0"、"7"或undefined,否则可能产出<hnan></hnan>或运行时报错 - 组件库中所有卡片、弹窗、侧边栏等复用单元,禁止硬编码
h1;若需语义标题,统一 fallback 到h3并配aria-labelledby - 特别注意:Vue 的
v-html或 React 的dangerouslySetInnerHTML若拼错数字(如写成"h7"),浏览器不报错,但大纲提取器会中断解析 - 没
<section></section>时:<h2>A</h2> <h2>B</h2>是平级兄弟节点,大纲里只有两个同级heading-level: 2 - 加
<section></section>后:<section><h2>A</h2></section><section><h2>B</h2></section>,每个h2都成为各自区块的顶层标题,heading-level仍为2,但它们互不隶属,可被屏幕阅读器独立跳转 - 更关键的是:每个
<section></section>内部允许从h1开始(语义上等价于外层h2),但前提是这个<section></section>真代表一个独立内容单元(如博客单篇、产品参数表) - 如果只用
<div class="card"> 包裹 <code>h3,它不会重置层级,反而造成跳级真正难的不是“有没有用
h1”,而是“它被谁包裹、在哪个语义容器里、和谁并列”。<main></main>下直接放<h1></h1>是安全的;中间插一个<div class="wrapper">,就等于加了一层不可见的结构干扰——这种细节,靠肉眼根本看不出,必须查 <code>aria-level或Accessibility Tree。
React/Vue 动态渲染时怎么避免生成非法 heading-level
用 props.level 渲染 <h></h> 很常见,但 runtime 值不可信,必须做三重过滤:
section 标签如何重置 heading-level 计数
<section></section> 是 sectioning root,它会让内部标题重新开始层级计数。这不是视觉分组,而是语义隔离:











