select元素无法实现多级下拉菜单,必须使用语义化ul/li嵌套结构,并配合aria属性、js状态管理及css热区优化确保可访问性与跨端兼容。

select 元素根本不能做多级下拉菜单,别试了。
必须用 ul/li 嵌套结构
浏览器对 ul 和 li 的默认语义、焦点流、屏幕阅读器播报都有成熟支持。用 div 堆砌会导致 Tab 键跳转错乱、子项无法被键盘访问,且 CSS :hover 定位极易失效。
- 顶级
ul加role="menubar" - 每个一级
li里放a或button,并带aria-haspopup="true"和aria-expanded="false" - 子菜单必须是父
li的直接子元素,且为ul(不是ol或div) - 子
ul加role="menu",子项li加role="menuitem"
:hover 在移动端完全不可靠
iOS Safari 和 Android Chrome 几乎不响应真机上的 :hover,纯 CSS 方案等于对手机用户关闭功能。
- 桌面端可保留
li:hover > ul作为辅助,但不能依赖它 - 移动端必须用 JS 切换类,比如
submenu-open,再通过.submenu-open > ul控制显隐 - 点击父项时,先关闭其他所有展开项,再切换当前状态
- 必须同步更新
aria-expanded值,否则屏幕阅读器读不出状态变化
悬停闪退是因为像素级空隙
鼠标移出父项瞬间菜单消失,不是 JS 写错了,是 CSS 热区断连。
- 子
ul绝对定位时,top: 100%后不要加margin-top: 1px—— 这 1px 就是闪退元凶 - 推荐方案:父
li加padding-bottom: 1px扩展热区,或子ul用transform: translateY(-1px)微调贴合 - 避免用
pointer-events: none隐藏子菜单,这会让键盘焦点直接跳过整个区域
最易被忽略的是 visibility: hidden 和 display: none 的区别:前者保留在焦点流中,后者彻底移除——键盘用户需要前者才能按 Tab 进入子菜单。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











