用select实现多级下拉菜单根本不可行,因其不支持嵌套、hover展开或层级结构;必须用ul/li+css+js构建,配合aria属性确保可访问性,并兼顾键盘、触屏及屏幕阅读器兼容。

用 select 实现多级下拉菜单根本不可行
HTML 原生 select 元素不支持嵌套、hover 展开或层级结构,强行用 optgroup 只能模拟“伪层级”,无法响应鼠标悬停、点击二级项、保持展开状态等真实菜单行为。浏览器会忽略 optgroup 内的任何 HTML 结构(比如再放一个 select 或 div),所有子选项都会被压平显示。
必须用 ul/li + CSS + JavaScript 构建
真正可交互的多级下拉菜单,得靠语义化列表配合样式控制显隐,再用 JS 处理展开/收起逻辑。关键点在于:
-
ul作为菜单容器,每个一级li包含文字和一个子ul - 子
ul默认display: none,hover 或 click 时改为block(或用 class 切换) - 必须阻止事件冒泡,否则点击二级项会同时触发一级的收起
- 移动端需额外处理 touch 事件,单纯 hover 在手机上无效
示例结构片段:
aria-expanded 和 aria-haspopup 不是可选,是必须加的
没有这些属性,屏幕阅读器完全无法识别这是可展开菜单,视障用户会直接跳过整个区域。常见错误是只加了 CSS 显隐却忘了 ARIA 标记:
- 一级
li的触发元素(如<a></a>或<button></button>)必须带aria-haspopup="true"和aria-expanded="false" - 每次展开/收起时,JS 必须同步更新
aria-expanded值为"true"或"false" - 子
ul应加role="menu",子项li加role="menuitem"
别用纯 CSS hover 实现,移动端会失效
很多教程只写 .menu li:hover .submenu { display: block; }——这在桌面端看似工作,但 iOS 和 Android 上 hover 触发不可靠,且无法键盘导航(Tab 键无法进入子菜单)。正确做法是:
- 用
click事件替代 hover,尤其对移动优先项目 - 为键盘用户提供
Enter和Space键支持(监听keydown) - 用
focusin/focusout模拟 hover 效果,兼容键盘操作 - 避免用
pointer-events: none隐藏子菜单,会导致焦点丢失
最简健壮逻辑:点击父项时,先关闭其他所有展开项,再切换当前子菜单显隐,并同步更新 ARIA 状态。
真正麻烦的不是写几行 HTML,而是让菜单在键盘、屏幕阅读器、触屏、缩放字体、高对比度模式下都一致可用。光靠结构和样式远远不够,JS 控制流和 ARIA 状态同步一旦漏掉一环,就等于没做。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











