必须套ul,nav是语义容器但不强制结构;直接放a标签虽合法却丢失可访问性——屏幕阅读器无法识别导航项,Tab顺序易混乱,推荐始终用ul+li包裹以满足辅助技术标准。

nav 必须套 ul 吗
不用。nav 是语义容器,不强制要求内部结构;直接放 a 标签也能通过 HTML 验证,但会丢失可访问性支持——屏幕阅读器无法识别“这是一组导航项”,键盘 Tab 顺序也容易混乱。
真正该关心的不是“能不能”,而是“值不值得省这个 ul”。常见错误是:为图省事写成 <nav><a href="/home">首页</a><a href="/about">关于</a></nav>,结果测试时发现 NVDA 或 VoiceOver 完全跳过整个区域。
- 推荐始终用
ul+li包裹导航链接,这是 AT(辅助技术)识别导航列表的事实标准 - 如果导航项动态生成、且逻辑上不是“并列入口”(比如带搜索框或登录按钮),那就别硬塞进
ul,单独拆出去更干净 -
nav里混用div和a是典型反模式——既没语义,又难样式控制,还破坏键盘导航流
ul 嵌套子菜单时怎么写才合法
子 ul 必须严格放在父级 li 内部,不能挂在 nav 或外层 ul 下。HTML 解析器会把错位的 ul 自动闭合或丢弃,导致 DOM 结构断裂、CSS 选择器失效、JS 获取不到节点。
正确写法示例:<nav><ul><li>产品<ul><li>手机</li><li>平板</li></ul></li><li>支持</li></ul></nav>
立即学习“前端免费学习笔记(深入)”;
- 每个子
ul前必须有li作为父容器,否则语义断裂,AT 无法建立层级关系 - 二级
ul不需要额外nav包裹——它只是主导航的延伸,不是独立导航区 - 若子菜单需键盘操作(如按 ↓ 展开),得加
aria-haspopup="true"和aria-expanded="false"到父a或li
为什么 display: flex 在 ul 上比 inline-block 更可靠
因为 inline-block 会吃掉 HTML 换行符产生的空白字符,导致 li 间出现无法用 margin 精确控制的缝隙;而 flex 把 ul 当作布局容器,天然无视源码换行,间隙完全由 gap 或 margin 控制。
更关键的是:flex 能让 li 自动等宽、居中、响应式收缩,inline-block 在小屏下容易溢出或折行错乱。
- 写
nav ul { display: flex; list-style: none; padding: 0; margin: 0; }就够了,不用额外清空li的块级行为 - 避免对
li设float: left——已废弃,清除浮动麻烦,且与现代布局冲突 - 如果要兼容 IE10/11,
flex仍可用,但别用gap,改用margin-right控制间距
aria-label 和 aria-current 哪些地方不能漏
aria-label 是给 nav 加的“名字”,告诉屏幕阅读器“这是主导航还是页脚快捷链接”;aria-current="page" 是标出当前页面对应的链接,否则用户无法感知“我在哪”。两者漏掉一个,残障用户就得靠猜。
常见疏忽:<nav aria-label="主导航"> 写了,但没给当前页链接加 aria-current="page";或者反过来,只标了当前页,却没声明导航类型,导致多个 nav 区分不开。
-
aria-label值要具体,比如"主导航"、"页脚资源链接",别写泛泛的"导航" -
aria-current="page"必须加在a标签上,不是li,且只加一个——多加或漏加都会误导 - 服务端渲染时,当前页判断逻辑出错会导致
aria-current错位,务必在上线前用读屏工具实测
aria-label 也来不及。



















