正确做法是全页仅一个main且为body直接子元素;section须有标题才具语义;header/footer应服务局部内容单元;p标签内禁止嵌套块级元素。

main 标签重复或嵌套导致辅助技术失效
浏览器允许写多个 <main></main>,但读屏器只会跳转第一个,其余被忽略;更严重的是把它塞进 <header></header>、<footer></footer> 或 <section></section> 里——这直接破坏“主内容”定位逻辑。
常见错误现象:
- 用
<main></main>包裹导航栏或页脚(误以为“主要区域”=“视觉上最显眼”) - 在 Vue/React 组件中每个组件都渲染一个
<main></main>,导致 SSR 后页面出现多个 - 给
<main></main>加role="main",其实它已自带该 role,冗余属性反而干扰部分旧版读屏器
正确做法只有一条:全页 DOM 中 <main></main> 必须是 的直接子元素,且仅出现一次。若需“局部主内容”,用 aria-labelledby + 普通容器替代。
section 缺少标题或滥用为布局容器
<section></section> 不是带语义的 <div>。W3C 明确要求:没有标题的 <code><section></section> 等价于 <div>,浏览器和爬虫不会将其识别为独立逻辑区块。<p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p>
<p>典型误用场景:</p>
<ul><li>把整个响应式栅格外层写成 <code><section class="container"></section> —— 它不承载内容意图,只是布局壳,必须用 <div>
<li>在博客列表页,对每条 <code><article></article> 外再套一层 <section></section> —— <article></article> 已含完整语义,叠加 <section></section> 反而污染大纲层级
<h2></h2>~<h6></h6> 的 <section></section>,Lighthouse 的“结构化数据”项立刻报红判断依据很简单:删掉这个 <section></section>,里面的内容还能单独被理解吗?不能 → 改用 <div>;能,且有自然标题 → 才配得上 <code><section></section>。
header 和 footer 被当成“顶部横条”和“底部横条”硬套
<header></header> 和 <footer></footer> 是局部语义,不是全局占位符。它们描述的是“某个内容单元的头部/尾部元信息”,而非整页顶栏底栏。
容易踩的坑:
- 把全站主导航写成
<header><nav>…</nav></header>——<nav></nav>本身已是地标(landmark),再包<header></header>属于语义叠加,且违反“<header></header>不应含<nav></nav>”的嵌套规则 - 在
<article></article>里漏掉<header></header>,只放<h1></h1>—— 错失声明作者、发布时间、分类等元数据的机会 - 把版权信息塞进页面级
<footer></footer>里的<section></section>,结果搜索引擎把“© 2026”当成本文结尾内容索引
真实用法:<header></header> 可以出现在 、<article></article>、<section></section> 内部,只要它服务该上下文的标题与引言;<footer></footer> 同理,但禁止塞 <form></form> 或 <nav></nav> —— 那些不属于“尾部元信息”。
p 标签里塞块级元素引发 DOM 结构断裂
这不是语义问题,是解析规则铁律:<p></p> 只接受行内容(phrasing content)。一旦你写 <p></p>
<div>text</div>
<p></p>,把 <div> 插到外面,DOM 树彻底变样。
<p>后果比想象中更隐蔽:</p>
<ul>
<li>CSS 选择器 <code>p > div 永远不生效
document.querySelector('p').children 返回空 NodeListinnerHTML 动态插入含 <div> 的字符串,实际渲染位置完全不可控
<p>修复方式只有两个:要么换容器(用 <code><section></section> 或 <div> 替代 <code><p></p>),要么改内容(把 <div class="item"> 换成 <code><span class="item"></span>,或直接用 <ul></ul> + <li>)。
真正难的不是记住哪些标签存在,而是每次敲下 时,先问一句:这个结构,屏幕阅读器会怎么读?搜索引擎会怎么索引?DOM API 会怎么暴露它?错一次,修复成本远高于初始选对。



















