必须为每个nav添加唯一aria-label(如“主导航”“页面目录”),否则屏幕阅读器仅读作重复的“navigation”,无法区分用途;已有可见标题时应优先用aria-labelledby而非aria-label。

多个
因为没加aria-label。浏览器和读屏软件只把nav识别为“导航”这个抽象类型,不区分用途。同一页面出现两个nav但都没标注,用户听到两次“navigation”,完全无法判断哪个是顶部菜单、哪个是侧边目录。
必须给每个nav加唯一标识:
-
<nav aria-label="主导航">—— 用于页眉横向菜单 -
<nav aria-label="页面目录">—— 用于文章内锚点列表 -
<nav aria-label="页脚导航">—— 仅限站点级入口(如隐私政策、合作联系)
如果已有可见标题(比如<h2 id="toc-title">目录</h2>),优先用aria-labelledby="toc-title",比空字符串aria-label=""更可靠。
局部导航(如文章目录)能用
能用,但有严格前提:它必须是一组真实、可跳转的a链接,且指向当前文档内带id的语义区块(如<section id="install">)。不是所有“看起来像目录”的结构都适合套nav。
立即学习“前端免费学习笔记(深入)”;
以下情况禁用nav:
- 纯JS驱动的锚点跳转(如
<button onclick="scrollTo('#faq')">)—— 缺少href,读屏器无法识别为导航 - 动态渲染未完成的目录(React/Vue组件尚未挂载,DOM里
nav下为空或只有占位符)—— 辅助技术直接忽略 - 评论区的“跳转到第3条评论”链接 —— 属于内容内操作,非全局或节级导航
面包屑是个特例:ol.breadcrumb比nav更合适,W3C明确建议不用nav包裹它。
全局导航和局部导航混在同一个
语义坍塌。一个nav代表“一组用途一致的导航链接”,混入不同层级的链接(比如顶部菜单+本页目录+页脚快捷入口),会让读屏器失去上下文判断能力,SEO也难以提取有效导航路径。
正确拆分方式:
- 主导航(跨页面跳转)→ 单独
<nav aria-label="主导航"> - 页面目录(仅跳转本页
id)→ 单独<nav aria-label="页面目录"> - 页脚核心入口 → 单独
<nav aria-label="页脚导航">,且只放真正重要的站点级链接
绝对不要嵌套nav:<nav><nav>...</nav></nav>是HTML语法错误,现代浏览器会自动修正DOM结构,导致预期外的语义丢失。
为什么用包导航项不是可选项,而是硬性要求
因为键盘Tab顺序、屏幕阅读器列表播报、以及CSS布局控制都依赖这个结构。直接写<nav><a>首页</a><a>产品</a></nav>看似省事,实际会触发三类问题:
- 读屏器无法告知用户“这是个包含2项的链接列表”,只会逐个读出“首页,链接”“产品,链接”,丢失集合语义
- 键盘用户按Tab时,焦点可能跳过部分链接(尤其在Flex布局下,无
ul/li结构时浏览器对Tab顺序处理不一致) - CSS中想用
:first-child或:last-child控制首尾间距会失效,因为a不再是同级兄弟元素
哪怕视觉上是横排,也要用<ul><li><a>首页</a></li></ul>结构,再用display: flex布局——结构语义和视觉表现必须解耦。



















