是标记页面主要内容区域的唯一正确且必须使用的方式,它自带隐式role="main"语义,手动添加role属性会导致重复播报、语义污染及可访问性检测失败。

为什么不能用 div role="main" 替代 <main></main>
浏览器和主流屏幕阅读器(NVDA、VoiceOver、JAWS)都依赖原生 <main></main> 的隐式角色做地标识别,而 div role="main" 在部分旧版 Safari 或 IE 中可能被忽略或误判。更关键的是:<main></main> 元素天然具备“全页唯一”校验机制——若出现多个,DevTools 的 Accessibility 面板会直接标红警告;div role="main" 则完全靠人工保证,极易出错。
常见错误现象:
- 页面滚动十几屏后,用户按 Ctrl+Option+U(VoiceOver)或 D 键(NVDA)列出地标,却找不到 “main” 项
- Chrome DevTools → Accessibility → Landmarks 面板中显示 “No landmarks found”,但 DOM 里明明写了
div role="main"
<main></main> 必须包裹什么内容才符合语义
它必须只包裹真正对当前页面上下文起决定性作用的内容,比如文章正文、产品详情、表单主体,而不是整个 或把 <header></header>、<nav></nav> 一并包进去。
典型误用场景:
- 用
<main></main>包裹整个页面布局(含导航、页眉、侧边栏),导致屏幕阅读器用户跳转后仍需绕过一堆非核心内容 - 在 CMS 模板中把
<main></main>放在最外层 layout div 里,结果每个子页面都继承了同一套冗余结构 - 动态渲染时,JS 插入新内容后没重置
<main></main>范围,导致地标指向已失效的 DOM 节点
多个页面共用同一套模板时,<main></main> 怎么避免重复或遗漏
服务端渲染(SSR)或静态站点生成(SSG)项目中,<main></main> 往往由 layout 组件统一提供,容易在嵌套路由或条件渲染下漏掉或重复。解决关键是:把 <main></main> 的开闭标签严格绑定到页面级内容容器,而非布局壳。
实操建议:
- React/Vue 中,让每个页面组件自己提供
<main></main>,layout 组件只负责<header></header>、<nav></nav>、<footer></footer>,不碰<main></main> - Next.js 使用
getStaticProps或getServerSideProps渲染的页面,确保返回的 JSX 根节点是<main></main>,而非<div> <li>检查最终 HTML:用 Chrome 右键 → “View page source”,确认全页只有一个 <code><main></main>开始标签,且其内部不嵌套另一个<main></main> - 打开 Chrome DevTools → Elements → 右键任意元素 → “Accessibility” → 查看 Landmarks 栏是否列出
main,并点击跳转是否准确落到正文开头 - NVDA 用户:按 Insert+F7,查看地标列表中是否有 “main” 且描述为 “main landmark”(不是 “region” 或 “group”)
- 禁用 CSS 后浏览页面,确认
<main></main>内容仍在视觉流中处于主体位置,没有因浮动/绝对定位脱离文档流
如何验证 <main></main> 是否生效
不能只看代码写了没,得看辅助技术是否真能识别。最直接的验证路径是:
最容易被忽略的一点:当页面使用了 display: contents 或 visibility: hidden 修饰 <main></main> 的父容器时,<main></main> 本身虽在 DOM 中,但会被辅助技术跳过——必须确保它在可访问树中是 exposed 且 visible 的。











