页面只能有一个main标签,这是HTML5规范强制要求;它必须作为body的直接子元素,仅包裹当前URL独有、不可复用的核心内容,重复或嵌套会导致屏幕阅读器跳转失效、Lighthouse报错及SEO错乱。

页面里能有几个 <main></main> 标签
只能有一个。不是“建议”,是 HTML5 规范强制要求:<main></main> 必须是文档中唯一的主内容地标(landmark)。浏览器不报错,但 Lighthouse 会明确提示 “Document has more than one main landmark”,NVDA、VoiceOver 等读屏软件在跳转时可能忽略全部或随机选一个——用户根本进不到正文。
常见误用场景:
- React/Vue 的每个路由组件(如
Home.tsx、About.tsx)都写了<main></main>—— 应只由最外层页面组件(如app/page.tsx)包裹一次 - 服务端模板循环渲染卡片时,误把每张卡片都包上
<main></main>—— 这会让语义彻底失效 - Next.js 的
app/layout.tsx里提前塞了<main></main>—— 这是全局壳层,不是页面主体
<main></main> 能不能嵌套在 <header></header> 或 <footer></footer> 里面
不能。W3C 规范白纸黑字禁止:<main></main> 不得作为 <header></header>、<footer></footer>、<nav></nav>、<aside></aside> 的后代元素。
错误写法:<header><main>...</main></header> —— 屏幕阅读器大概率直接跳过该 <main></main>,因为它被判定为“导航上下文中的内容”,而非独立主区域。
正确结构必须是平级并列:
<header></header> <main><h1>文章标题</h1><p>正文...</p></main> <footer></footer>
哪怕视觉上你想让 <main></main> “看起来在页眉下面”,DOM 层级也必须和 <header></header> 同级,且都是 的直接子元素(或至少是语义中立容器如 <div> 的直接子元素)。
<h3>
<code><main></main> 里该放什么、不该放什么
判断标准只有一条:这块内容是否「随 URL 变化、不可跨页复用」。复制粘贴到另一个页面还能原样用?那它就不属于 <main></main>。
✅ 允许放入:
-
<h1></h1>~<h6></h6>(注意:若<header></header>已有站点级<h1></h1>,<main></main>内建议从<h2></h2>起始) -
<p></p>、<section></section>、<ol></ol>、<form></form>(独立提交用途)、<article></article> - 商品列表、博客正文、仪表盘核心数据面板等真正构成当前页面主题的内容
❌ 必须移出:
-
<nav></nav>(包括面包屑、顶部导航、侧边栏导航) -
<footer></footer>(版权信息、备案号) -
<aside></aside>(推荐位、广告、相关文章) - 网站 Logo、全局搜索框(即使只在当前页显示,逻辑上仍是复用模块)
SPA 和无障碍兼容要注意什么
单页应用里,<main></main> 的位置不能变,但内容要随路由动态更新。不要用 JS 整体替换 <main></main> 标签,而应只更新其子节点。
可访问性方面,<main></main> 自带隐式 role="main",无需额外添加。但为提升兼容性(尤其旧版读屏器),建议:
- 给
<main></main>加id,并用aria-labelledby关联一个可见标题(如<main id="content" aria-labelledby="main-title"><h2 id="main-title">最新动态</h2></main>) - 避免用
display: none隐藏<main></main>—— 这会让读屏器彻底忽略它;如需视觉隐藏,用visibility: hidden+position: absolute并严格测试 - IE 不支持
<main></main>,若仍需兼容,可用<div role="main"> 回退,但必须配 <code>aria-labelledby,否则语义不完整最容易被忽略的点:开发者工具里 Ctrl+F 搜
<main></main>,确认全页只有一对;SPA 切换路由后,再搜一次——很多项目上线后才发现多个路由组件各自渲染了<main></main>,问题藏得很深。

















