role="navigation" 应加在真正承担主导航功能的容器上,优先使用语义化标签;仅当无法修改html结构时才用role="navigation",并配合aria-label等属性明确用途。

role="navigation" 应该加在哪个元素上
它不是随便套在 <div> 或 <code><nav></nav> 上就完事的。语义正确性取决于结构意图:如果页面顶部有一组主导航链接(比如首页、产品、关于、联系),那就该用 <nav></nav> 元素,而不是手动加 role="navigation"。只有在无法修改 HTML 结构(例如第三方组件、遗留模板)时,才退而求其次用 role="navigation" 显式声明。
常见错误是给多个容器都加这个 role,比如页眉、侧边栏、页脚各来一个 role="navigation" —— 屏幕阅读器会把它们全识别为“导航”,但缺乏区分。正确做法是:只对真正承担主导航功能的容器使用,必要时配合 aria-label 或 aria-labelledby 标明用途:
<div role="navigation" aria-label="主菜单"> <a href="/">首页</a> <a href="/products">产品</a> </div>
和原生
<nav></nav> 是语义化标签,浏览器和辅助技术默认赋予它 role="navigation",还自带隐式 ARIA 特性(如可聚焦、键盘导航支持)。手动加 role="navigation" 不会自动获得这些行为,得自己补。
- 如果用了
<nav></nav>,不用再写role="navigation"—— 重复声明无害但冗余 - 如果用了
role="navigation"却没用<nav></nav>,要确保内部链接能被键盘访问(tabindex通常不需要,除非内容动态生成) -
<nav></nav>支持 CSS 伪类:focus-within等现代特性;纯role容器不享受这类便利
什么情况下必须用 role="navigation"
典型场景是封装好的 UI 组件库或 CMS 模板,你只能改属性、不能动标签名。比如 Vue 组件返回的是 <div class="header-nav">,但你需要它被读屏软件识别为导航区。
<p>这时加 <code>role="navigation" 是合理且必要的。但要注意两点:
- 避免嵌套:不要在已有
<nav></nav>内部再加role="navigation",会导致重复播报 - 别滥用:面包屑、分页、页脚链接列表一般用
role="navigation"就过度了,更适合role="group"或直接靠语义化标签(如<ol></ol>+aria-label) - 测试验证:用 Chrome 的 Accessibility DevTools 或 NVDA/Firefox 组合,确认焦点进入后确实播报 “navigation” 而非 “group” 或 “region”
容易忽略的键盘与焦点问题
加了 role="navigation" 并不等于它就能被键盘用户自然访问。如果容器本身不可聚焦(比如普通 <div>),键盘用户 Tab 进去时可能直接跳过整个区域。
<p>解决方案不是加 <code>tabindex="0"(这会让它出现在 Tab 顺序里,但破坏逻辑流),而是确保导航项本身是可聚焦的(<a></a>、<button></button>),且容器有明确的起始/结束边界。必要时用 aria-labelledby 关联标题,帮助屏幕阅读器建立上下文:
<h2 id="mobile-nav-title">移动菜单</h2> <div role="navigation" aria-labelledby="mobile-nav-title"> <a href="/home">首页</a> </div>
真正麻烦的是那些用 div + click 模拟链接的旧代码——光加 role="navigation" 没用,必须补 tabindex="0"、role="link"、aria-label 和键盘事件(Enter/Space),否则对残障用户就是不可用的。











