一个页面只能有一个main标签,是W3C规范强制要求;多写、嵌套或误放会导致读屏器跳转失效、SEO摘要错乱、Lighthouse报duplicate-main错误,因其是屏幕阅读器“M键直达主内容”的唯一语义锚点,且必须为body直接子元素,内部仅含不可跨页复用的核心内容。

一个页面只能有一个 main 标签,不是“建议”,是规范强制要求;多写、嵌套或误放,会导致读屏器跳转失效、SEO摘要错乱、Lighthouse 直接报 duplicate-main 错误。
为什么浏览器不报错,但必须当真
HTML 解析器对重复 main 宽容,不会中断渲染——但这不等于它被认可。屏幕阅读器(如 VoiceOver、NVDA)依赖 main 作为「按 M 键直达主内容」的唯一锚点,遇到第二个就可能随机忽略、跳过全部,或反复播报“主内容开始”,用户无法预测行为。Lighthouse 和 axe 工具会明确标红 duplicate-main,而 DevTools 却沉默,极易被忽略。
- SPA 中每个路由组件都写
→ hydration 后 DOM 留下多个实例{children} - 服务端模板未做条件判断,列表页和详情页共用同一套
main包裹逻辑 → 渲染出并存或嵌套结构 - Next.js 的
app/layout.tsx里直接放→ 全局壳层不该承载页面级语义
main 必须是 body 的直接子元素,不能嵌套在 header/nav/footer 里
这不是兼容性问题,是语义冲突:main 表达的是“整页不可替代的核心内容”,而 header、nav、footer 是全局分区元素。规范明文禁止 main 作为它们的后代。错误写法如 ,会让辅助技术降级或跳过该 main。
- 正确结构只有一种:
-
header作为main的子元素是允许的,但仅限当前页面独有元信息(如文章标题+发布时间),不是网站全局头部 - Vue/React 中注意:若组件模板用
包裹多个根节点,需确保main不被意外塞进父级语义区块内
什么该进 main,什么必须踢出去
判断标准极简:如果这块内容复制粘贴到另一个页面还能原样用,那它就不该进 main。它不是“视觉上最显眼的区域”,而是“语义上不可复用的内容边界”。
- ✅ 应包含:
正文、商品列表、独立、搜索结果页主体 - ❌ 不应包含:
全局导航、版权、侧边推荐、面包屑、网站 Logo 或登录入口 - ⚠️ 容易混淆:
内的“客服入口”按钮——它服务主题但不构成主题本身,应放在或,而非mainSPA 路由中如何安全更新 main 内容
React/Vue 最稳妥的做法是:只在根 Layout 组件中声明一次
,所有子路由内容作为其直接子节点动态替换,而不是让每个页面组件自己渲染一个。- ✅ 正确:
(React Router v6),或(Vue Router) - ❌ 错误:在
ArticlePage里写,又在ProfilePage里重复 - ⚠️ 特殊情况(如 404 页面):不能靠
,要确保整个生命周期内{error ? : } main节点只存在一个实例——可通过状态控制是否渲染该节点本身
最容易被忽略的一点:它不是视觉容器,也不承担样式职责;滥用
main做布局撑开或 CSS 作用域,反而会掩盖真正的语义意图。 - ✅ 正确:
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











