屏幕阅读器依赖html语义地标导航,而非视觉布局;错误嵌套、重复或遗漏关键地标(如必须唯一且顶层)、缺失标题或焦点元素等结构问题会导致地标失效。

屏幕阅读器不是靠“看布局”导航,而是靠 HTML 结构里的隐式地标(landmark)角色定位——写对标签名只是起点,错位嵌套、重复使用或遗漏关键区域,会让整个语义路标系统失效。
为什么写了 <nav></nav> 但 NVDA 还是跳不过去
常见错误现象:用户按 Insert+Tab 切换地标时,“导航区域”不出现,或读作“区块”而非“导航”。根本原因不是 CSS 隐藏,而是结构违规。
-
<nav></nav>被包在<table>、<code><ul></ul>或<div role="group"> 里——这些父容器会中断地标传播,浏览器可能直接丢弃该 <code><nav></nav>节点 -
<nav></nav>内部没放可聚焦元素(比如只写了文字,没写<a></a>或带tabindex="0"的容器) - 页面存在多个
<nav></nav>却没加aria-label,导致辅助技术无法区分用途(如主导航 vs 页脚链接) - 用
<div class="nav"> + <code>role="navigation"替代原生<nav></nav>,丢失了隐式键盘焦点管理逻辑<main></main>必须唯一且不能嵌套的硬约束这是所有语义路标中最不可妥协的一条:
<main></main>是屏幕阅读器定位“核心内容”的唯一锚点。Lighthouse 报 “Multiple main landmarks” 不是警告,是直接判定无障碍失败。- 正确结构只能是
→<header></header>、<main></main>、<footer></footer>并列;<main></main>不能出现在<header></header>、<aside></aside>或<section></section>内部 - 如果主内容区被包裹在某个组件壳里(比如 React 的
<layout></layout>),必须确保最终输出的 DOM 中<main></main>是顶层子节点 -
<main></main>里只包一个<section></section>?大概率冗余——除非这个<section></section>确实有独立标题且需参与大纲生成,否则直接用<main></main>+<h1></h1>更干净
<section></section>和<article></article>混用导致大纲断裂二者语义权重完全不同:
<article></article>是可独立分发的内容单元(如博客正文),<section></section>只是主题分组(如“参数详情”小节)。误用会破坏辅助技术的内容优先级判断。-
<section></section>必须带<h2></h2>–<h6></h6>标题,否则会被 NVDA 当作无效节点跳过;没有标题的“分组”,一律用<div> <li> <code><article></article>内部的<header></header>/<footer></footer>属于该文章上下文,不影响外层页面大纲;但<section></section>内部的<header></header>仍属于当前文档层级 - 轮播图容器、网格卡片列表、纯视觉分隔线——这些没有语义主题的区域,不要强行套
<section></section>,<div> 更诚实 <h3>如何验证语义路标是否真实生效</h3> <p>别只靠 DevTools 查看标签名。真正起作用的是浏览器暴露给辅助技术的 ARIA role、name 和 level。Chrome DevTools 的 Accessibility 面板里,展开“Landmarks”节点才能看到实际识别出的地标结构。</p> <ul> <li>用 NVDA 按 Insert+F7 查看地标列表:如果 <code><main></main>没出现,或<nav></nav>显示为 “region”,说明结构已被破坏 - 检查每个
<nav></nav>的 computed role 是否为navigation,name 是否由aria-label或内部第一个<h2></h2>提供 -
<aside></aside>如果被读作 “complementary”,说明语义正确;若读作 “region”,大概率是它被包在了<div> 或位置不对(比如放在 <code><main></main>外但未紧邻主体)最常被忽略的点:语义路标不是写完就自动生效的,它依赖严格的父子关系和唯一性约束。任何一个环节松动,整个导航骨架就会塌陷——而这种问题,往往在视觉上完全看不出来。
- 正确结构只能是











