nav标签必须包裹完整导航结构且配aria-label,不能只包单个链接;须用ul/li组织多个导航项,禁混入搜索框等非导航元素。

nav 标签不是“加个样式容器”,而是告诉浏览器和读屏器“这里是一组导航链接”。用错结构,Tab 键跳不过去、NVDA 读不出菜单、Lighthouse 直接报 Navigation landmark not present。
必须用 ul 包裹多个 a,不能只包单个链接
常见错误:<nav>@#@#@#@#@#@#@#@#@#@0</nav>——这会被辅助技术降级为普通段落,失去导航地标作用。
- 正确写法是用
ul(或ol)包裹所有导航项:<nav aria-label="主导航"><ul> <li>@#@#@#@#@#@#@#@#@#@0</li> <li>@#@#@#@#@#@#@#@#@#@2</li> </ul></nav> - 视觉上不用列表样式?没问题,CSS 可以清掉
list-style和margin/padding,但语义结构不能省 - 极简场景下可省略
ul,直接写多个a,但仅限项数少、无嵌套、无障碍要求不高的内部系统页面
aria-label 或 aria-labelledby 是硬性要求,不是可选项
没有这个属性,nav 就等于没命名。屏幕阅读器只会读 “navigation”,用户完全不知道这是主菜单、侧边栏还是页脚链接组。
- 固定名称(如“主导航”“页脚导航”)直接用
aria-label="主导航" - 需要翻译或动态生成标题(如后台多语言系统),改用
aria-labelledby="nav-title",并配一个不可见但可访问的标题:<h2 id="nav-title" class="visually-hidden">管理面板导航</h2> - 别两个属性同时写——
aria-labelledby会覆盖aria-label,白写 - 已有可见标题(比如
<h2>网站导航</h2>)时,优先用aria-labelledby关联,更准确
别把搜索框、登录按钮、主题切换塞进 nav
nav 的语义边界非常明确:只包含以“跳转”为目的的链接集合。混入其他功能控件,会导致键盘导航卡住、自动化测试报 Landmark contains non-navigation content。
- 搜索框应独立放在
<header></header>内,或用<search></search>标签包裹 - 登录/注册按钮属于操作入口,放进
<header></header>右侧区域,或用户菜单弹层里 - 唯一例外:按钮本身触发锚点跳转(如
<button onclick="scrollTo(0,0)">回到顶部</button>),且明确作为导航手段时,可以保留在nav中 - 面包屑(breadcrumbs)可以用
nav,但必须加aria-label="当前位置"明确意图
移动端收起侧边栏时,别用 display: none
用 display: none 隐藏 nav,会让整个导航区块从可访问树中消失:键盘用户无法 Tab 进入,读屏器直接跳过,SEO 也抓不到。
- 推荐方案:用
transform: translateX(-100%)+inert属性控制交互状态 - 保持 DOM 存在,确保焦点可到达、语义可读取
- 若需兼容旧浏览器(如 IE11),可用
visibility: hidden+position: absolute移出视口,但要手动管理焦点流 - Flexbox 布局下注意:
nav ul设了display: flex后,li默认不占宽,记得给a加flex: 1或min-width,否则移动端点击热区塌缩
最常被忽略的一点:同一页面多个 nav 必须用 aria-label 或 aria-labelledby 明确区分用途。否则读屏器连续报出“导航、导航、导航”,用户根本分不清哪个是顶部菜单、哪个是侧边工具栏、哪个是页脚分类。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











