必须直接置于 下且不可嵌套在 或 中,否则语义失效、读屏软件误判;其内容仅限跳转链接与导航控件,须用 aria-label 等明确标识用途,并同步 aria 状态以保障无障碍访问。

<nav></nav> 必须直接放在 下,不能嵌在 <header></header> 或 <footer></footer> 里——否则语义失效,读屏软件可能跳过或误判。
为什么 <nav></nav> 不能套在 <header></header> 里
很多人图方便把 <nav></nav> 写成 <header><nav>...</nav></header>,这会让辅助技术(AT)丢失导航意图。HTML5 规范明确:<nav></nav> 是独立的 landmark,不是装饰容器。
- 浏览器和读屏工具靠标签语义识别“这是导航区”,嵌套后会降级为普通内容
- 多个
<nav></nav>共存时(比如页脚也有快捷链接),嵌套结构会让 AT 无法区分层级 - Lighthouse 会报错
Navigation landmark not present,即使 DOM 里有<nav></nav> - 正确结构是
<header></header><nav aria-label="主导航"></nav><main></main>
<nav></nav> 里能放什么、不能放什么
<nav></nav> 的语义边界非常严格:只容纳以“跳转”为目的的链接或导航控件。塞错东西会触发无障碍检测失败。
- ✅ 允许:
@#@#@#@#@#@#@#@#@#@0、带aria-controls的汉堡按钮、面包屑(需加aria-label="当前位置") - ❌ 禁止:
<input type="search">、登录表单、语言切换下拉、主题切换按钮——这些该用<search></search>、<form></form>或<section aria-label="语言选择"></section> - ⚠️ 常见陷阱:把搜索框和导航链接一起包进
<nav></nav>,键盘用户 Shift+Tab 会卡在输入框里出不来 - 子菜单用嵌套
<ul></ul>即可,不要另起一个<nav></nav>——语义上它仍是同一导航上下文
多个 <nav></nav> 共存时怎么区分用途
一个页面出现顶部主菜单、侧边分类、页脚资源链接、面包屑时,不标注就会让读屏软件全念成“导航”,用户根本分不清哪个是哪个。
- 必须为每个
<nav></nav>提供唯一可访问标识,优先用aria-label,如aria-label="主导航"、aria-label="页脚资源链接" - 避免写英文或模糊描述,比如
"Footer navigation"或"nav-2",中文更直接:aria-label="文章分类导航" - 需要动态更新或翻译时,改用
aria-labelledby="bc-title",再配一个不可见但可读的<h2 id="bc-title">当前位置</h2> - 别同时写
aria-label和aria-labelledby,后者优先级更高,前者会被忽略
响应式折叠菜单的 ARIA 同步要点
移动端把导航收进汉堡菜单,光靠 CSS display: none 切换是不够的——键盘用户按 Tab 仍会进入隐藏区域,读屏也读不到状态变化。
- 触发按钮必须带
aria-expanded="false",点击后同步改为"true" - 按钮要加
aria-controls="nav-menu-id",指向对应<nav id="nav-menu-id"></nav> -
<nav></nav>不要用hidden属性(它会彻底移出可访问树),改用aria-hidden="true"并随状态更新 - 展开时确保焦点进入第一个
<a></a>或<button></button>,关闭时焦点回退到触发按钮 - 纯 CSS 实现的
:checked + .nav也要注入这些 ARIA 属性,否则对键盘和读屏无效
最常被忽略的是:哪怕只有一处 <nav></nav>,没加 aria-label 就算语义残缺;而一旦用了多个,又不加区分标识,反而比不用更糟。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











