一个页面必须且只能有一个,它是文档唯一主语义锚点;至须严格逐级嵌套、不可跳级,或内可独立设,但需满足语义隔离条件。

一个页面到底该有几个 <h1></h1>
只有一个 <h1></h1> 是硬性语义要求,不是“建议”。它代表整个文档的唯一主旨,搜索引擎和屏幕阅读器都依赖这个信号定位核心内容。多出一个,比如 CMS 模板里塞了个 <h1></h1> Logo,正文又加一个 <h1></h1> 标题,结果就是大纲分裂——两个节点都被识别为根,辅助技术会困惑“哪个才算主?”
例外只发生在语义隔离场景:<article></article> 或 <section></section> 内部允许有自己的 <h1></h1>,但前提是这个区块能独立分发(比如博客列表页里的单篇摘要)。普通卡片、侧边栏、表单区块不在此列,用 <h2></h2> 更安全。
常见踩坑点:
-
<h1></h1>被包裹在<div class="wrapper"> 里,看似在 <code><main></main>下,实则中间插了一层无语义容器,破坏了直接父子关系 - JS 动态插入标题时没清理旧节点,导致 DOM 中残留多个
<h1></h1> - CSS 隐藏了某个
<h1></h1>却没删标签,结构仍在,但对用户不可见 - 放在
<main></main>直接子级的<h2></h2>,就是一级章节 - 放在
<section></section>内的<h3></h3>,哪怕数字比外面的<h2></h2>小,也会被识别为该<section></section>的顶层标题 - 如果
<h3></h3>被塞进<p></p>或<div>,它就脱离了合法上下文,部分读屏器直接忽略 <h3>为什么 <code><section></section>和<article></article>会影响标题解析<section></section>不是“装内容的盒子”,它是 sectioning root,会重置内部 heading 的隐含层级计数。没有它,所有<h2></h2>~<h6></h6>都在同一个全局大纲树里平铺;有了它,每个区块获得独立上下文。举个实际例子:
<main><h2>产品参数</h2> <section><h3>尺寸</h3> <p>长宽高...</p> </section><section><h3>材质</h3> <p>铝合金...</p> </section></main>这里两个
<h3></h3>是并列的子节,属于同一个<h2></h2>下的分支。但如果去掉<section></section>,直接写<h3></h3>,它们就会被当成跳级节点,Accessibility 面板标红警告。注意:空的
<section></section>仍会进入大纲,显示为“无标题”,对可访问性不利——每个<section></section>必须以对应层级的 heading 开头。怎么快速验证标题结构是否合理
别等上线再查。打开 Chrome DevTools → Elements 面板 → 右键任意
<h1></h1>~<h6></h6>元素 → “Inspect ARIA attributes”,看aria-level是否连续、是否符合你预设的内容逻辑。重点盯三处:
-
<h1></h1>是否唯一,且是<main></main>的直接子元素(中间不能有<div>) <li>是否存在 <code><h2></h2>后直接<h4></h4>这类跳级 - 每个
<section></section>、<article></article>是否以<h2></h2>或更高层级 heading 开头
最常被忽略的,不是“用了什么标签”,而是“它在哪儿、被谁包裹、和谁并列”。结构问题往往藏在嵌套深处,而不是标签本身。
-
<h2></h2> 到 <h6></h6> 的嵌套必须连续,不能跳级
跳级不是样式问题,是语义断裂。写 <h2></h2> 后直接跟 <h4></h4>,浏览器不会报错,但大纲生成算法会强行把 <h4></h4> 当作 <h3></h3> 的子项推断层级,而实际内容逻辑可能完全不匹配——屏幕阅读器用户导航时会卡在错位的结构里。
真正决定层级归属的,不只是标签名,还有它所处的语义容器:











