bootstrap 5 默认禁用 hover 触发二级菜单,仅支持点击;需同时修正 css 定位、显式重置 display、添加 focus-within 支持,并用 js 初始化子菜单实例以保障可访问性与移动端兼容。

Bootstrap 5 默认不支持鼠标滑过(hover)触发二级菜单,这不是你写错了,是框架主动禁用的——它只响应点击(click),且不初始化嵌套的 dropdown-menu。强行加 :hover .dropdown-menu { display: block } 会破坏可访问性、导致移动端点击后菜单闪退、键盘焦点失效,甚至让 Popper.js 定位错乱。
为什么纯 CSS hover 规则在 Bootstrap 5 里大概率失效
常见错误现象:二级菜单没显示、飞出屏幕、鼠标一移开就立刻收起、移动端点一下就全关了。
-
.dropdown-item:hover .dropdown-menu不生效,是因为.dropdown-item缺少position: relative,子菜单的left: 100%会相对于body定位,直接跑出视口 - Bootstrap 5 默认给嵌套的
.dropdown-menu .dropdown-menu加了opacity: 0和visibility: hidden,而display: block无法覆盖这些声明 - 原生 JS 没绑定二级菜单的事件,
data-bs-toggle="dropdown"只作用于一级,二级<ul></ul>根本没被Dropdown实例接管 - 没删掉默认的
display: none !important(尤其在bootstrap.min.css里),浏览器渲染时仍以它为准
必须加的最小 CSS(绕不开)
仅靠 JS 不行,CSS 层级和定位必须先对。以下四条缺一不可:
-
.dropdown-submenu { position: relative; }—— 让二级菜单能相对于它定位 -
.dropdown-submenu .dropdown-menu { top: 0; left: 100%; margin-top: -1px; }—— 贴右展开,-1px消除边框间隙 -
.dropdown-submenu .dropdown-menu { display: none; }—— 显式重置,覆盖默认!important -
.dropdown-submenu.show .dropdown-menu, .dropdown-submenu:focus-within .dropdown-menu { display: block; }—— 用show类或focus-within触发,兼容键盘用户
注意:.dropdown-submenu 是你自定义的 wrapper 类名,不能直接套在 <a></a> 或 <button></button> 上,得包一层 <li class="dropdown-submenu">。
JS 必须接管事件链(否则移动端/键盘全崩)
不能只监听 mouseenter 然后 show(),那会绕过 Bootstrap 的 ARIA 状态同步,屏幕阅读器读不出“菜单已打开”。正确做法是手动调用实例方法,并阻止默认关闭逻辑:
- 给二级触发项(如
<li class="dropdown-submenu"><a class="dropdown-toggle">Services</a></li>)加data-bs-toggle="dropdown"和data-bs-auto-close="outside" - 在 DOM 加载后,为每个
.dropdown-submenu初始化独立Dropdown实例:new bootstrap.Dropdown(el.querySelector('.dropdown-toggle')) - 监听
click事件,遇到.dropdown-submenu-toggle就e.stopPropagation(),防止冒泡触发父级hide() - 移动端需降级:用
matchMedia('(hover: none)')检测是否无 hover 支持,若有则禁用 hover 逻辑,只保留点击
Popper.js 可能干扰二级菜单位置,可在二级 <ul></ul> 上加 data-bs-popper="none" 关闭自动定位。
移动端和键盘导航的硬约束
iOS Safari 的 :hover 在触摸后仅维持极短时间,纯 CSS 悬停在真机上基本不可靠;而键盘用户按 Tab 进入二级项时,若没 focus-within 或 JS 同步 aria-expanded,菜单不会出现,也无法用 ESC 关闭。
最易被忽略的一点:二级菜单的 <ul></ul> 必须包裹在上级 .dropdown-menu 内部,结构形如 <li class="dropdown"><ul class="dropdown-menu"><li class="dropdown-submenu"><ul class="dropdown-menu"></ul></li></ul></li>。如果二级 <ul></ul> 被写到外面,鼠标一移出一级项,整个区域就失去 hover 或 focus 状态,菜单立刻收起。











