标签仅用于有明确导航意图的链接组,如主菜单、页脚地图、文章目录;须用结构,多需aria-label区分,当前页项须同时设class和aria-current="page",下拉菜单禁用role="menu"。

nav 标签必须包裹成组的、有明确导航意图的链接
不是所有带链接的容器都该用 <nav></nav>。它只适用于用户会主动用来跳转页面或站点区域的链接集合,比如顶部主菜单、页脚站点地图、文章内目录锚点列表。
常见错误是把单个“返回顶部”按钮、广告跳转链接、或者仅绑定 JS 事件但没 href 的伪链接塞进 <nav></nav> —— 这会让屏幕阅读器误判导航意图,甚至跳过整个区域。
多个 <nav></nav> 共存时(如主导航 + 页脚快捷链接),必须用 aria-label 区分用途:<nav aria-label="主导航"></nav><nav aria-label="页脚快速链接"></nav>
否则读屏无法区分,用户可能反复进入同一类导航。
ul + li 是导航列表的事实标准结构,不是可选项
去掉 <ul></ul> 和 <li>,哪怕用了 <nav></nav>,屏幕阅读器也会把所有链接连读成一串无结构的文本。NVDA 或 VoiceOver 不会识别“这是第几个菜单项”,也无法告知用户“共 5 项”。
正确写法必须是:<nav><ul>
<li>@#@#@#@#@#@#@#@#@#@0</li>
<li>@#@#@#@#@#@#@#@#@#@1</li>
</ul></nav>
别用 <div> 模拟列表并加 <code>role="list" —— 原生 <ul></ul> 在兼容性、稳定性、读屏支持上远超任何 ARIA 模拟方案。
当前页状态必须靠 class + aria-current 双重声明
仅靠 CSS 类如 class="active" 无法被屏幕阅读器感知。用户(尤其是视障用户)根本不知道“我现在在哪”,尤其当多个导航项文字相同(比如多个“详情”链接)时。
必须同时设置:
- 视觉样式:class="current"
- 语义标识:aria-current="page"(最常用值,表示当前页面级导航项)
注意:
• 避免用 aria-current="true" —— 它不是合法值,部分读屏会忽略或报错
• JS 动态更新导航高亮时,别只改 class,务必同步操作 aria-current 属性,否则辅助技术状态就断了
下拉菜单别乱用 role="menu"
普通网站主导航的下拉菜单,不需要 role="menu"。这个 role 是为操作系统级菜单(如右键菜单、应用菜单栏)设计的,会强制读屏切换到“应用模式”,反而打断正常浏览流。
常规下拉推荐做法:
• 用 <button></button> 触发展开,加 aria-expanded="false"
• 下拉内容用 <ul></ul> 包裹,每个子项仍是 <li><a></a></li>
• 展开时同步更新 aria-expanded 值,并确保键盘 Tab 能顺序进入子菜单
真正需要 role="menu" 的场景极少,比如模仿桌面软件菜单栏的复杂交互;绝大多数响应式导航,老老实实用 aria-expanded + 原生列表就够了。











