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

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



















