单页应用中必须复用初始的main元素,仅更新其内部内容,不可动态重建或在路由组件中重复定义main,否则会导致语义失效、无障碍支持崩溃及lighthouse评分下降。

单页应用里只能有一个,且不能动态重建
SPA 路由切换时,很多人习惯用 JS 把整个 main 元素替换成新内容,甚至新建一个 main —— 这会导致语义失效。浏览器只认 DOM 中第一个、且是 body 直接子元素的 main,其余全部忽略。
常见错误现象:
– 屏幕阅读器跳过主内容区,报 “no main landmark found”
– Lighthouse 的 “Landmark elements” 评分掉档
– DevTools Accessibility 面板里 main 的 role 是 generic 而非 main
- 始终复用初始渲染的
main元素,只替换其内部 HTML(如用innerHTML或框架的更新机制) - 不要在路由组件里写
<main>...</main>,那是骨架层的责任 - 如果用 React/Vue,把
main放在根组件外(如index.html或 Layout 组件顶层),确保它不随路由重挂载
用包裹可独立分发的路由内容,别滥用
article 表示能脱离当前页面单独存在、被 RSS 订阅或转发的内容单元;section 只是逻辑分组,删掉父级就失去上下文意义。SPA 中常混淆这两者。
使用场景判断:
- 博客详情页、新闻正文、用户个人主页 → 用
article,且必须有标题(h1–h6) - 首页的“热门文章”“推荐作者”等区块 → 用
section,每个需配h2等语义标题 - 表单页、设置页、404 页 → 没有独立分发价值,直接用
div或section,不强套article
注意:article 可以嵌套(如评论作为子 article),但 section 内部若无标题,会被 W3C Validator 报 warning。
导航和页脚的语义边界要按“全局”还是“局部”区分
nav 标签只用于主导航(即全站一级菜单),不是所有带链接的容器都该用它。SPA 中容易把 Tab 切换、步骤条、面包屑都塞进 nav,反而稀释语义。
- 顶部主导航、侧边栏全局菜单 → 合理用
nav - 页脚的“关于我们/隐私政策”链接 → 放在
footer内,用普通ul即可,不用nav - 文章内的“上一篇/下一篇” → 用
nav,但加aria-label="文章导航"明确作用域 - Tab 切换面板 → 用
role="tablist"+role="tab",比硬套nav更准确
同样,header 和 footer 可以出现在 article 或 section 内部,表示该区块自己的头尾,不与页面级冲突。
服务端渲染或 hydration 后必须校验无障碍属性是否存活
JS 动态渲染后,语义标签可能“形存实亡”:标签名还在,但辅助技术读不到角色或名称。尤其 SSR/SSG 场景下,hydration 不完整时常见。
验证方式(Chrome DevTools):
- 右键目标元素 → “Inspect Accessibility Properties”
- 确认
main的 role 是main,不是generic - 确认
nav的 name 是可读文本(如 “主导航”),而非空或 “nav” - 检查
article的name是否取自内部h1,而非 fallback 为 “article”
容易被忽略的点:CSS 的 display: none 或 JS 的 remove() 若没同步处理 aria-hidden,会让已挂载的语义节点“隐身”却不退出 landmark 流程——屏幕阅读器仍会尝试聚焦它,导致跳转错乱。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











