bootstrap 5 官方移除了对二级及以上 dropdown-menu 嵌套的支持,子菜单无法通过 hover 或 click 展开,需手动补全 css 或调用 dropdown 构造函数实现。

Bootstrap 5 不支持原生多级下拉菜单
直接说结论:Bootstrap 5 官方移除了对二级及以上 dropdown-menu 嵌套的支持,dropdown-menu 内再放 dropdown-menu 不会触发 hover 或 click 展开,CSS 也未定义相关样式。这不是你代码写错了,是框架刻意限制。
常见错误现象包括:鼠标悬停无反应、子菜单始终隐藏、点击父项后整个下拉消失。根源在于 Bootstrap 5 的 Dropdown JavaScript 插件默认只监听一级 .dropdown-item 的触发行为,且 CSS 中 .dropdown-menu .dropdown-menu 缺少定位修正和显隐控制。
手动补全 CSS 是最轻量的实现方式
不需要引入额外 JS 库,只需几行 CSS 覆盖默认行为即可让二级菜单可展开。关键是解决两个问题:子菜单的定位偏移、以及 hover/click 时的显隐控制。
使用场景:纯静态导航、不依赖 JS 交互增强的后台或文档站点。
-
.dropdown-menu .dropdown-menu必须设为position: absolute,并用top: 0和left: 100%向右展开(横向多级)或top: 100%向下展开(纵向) - 必须取消
.dropdown-menu的opacity: 0和visibility: hidden默认状态,改用display: none控制显隐,否则 transition 会失效 - 给
.dropdown-item:hover .dropdown-menu添加display: block触发显示(hover 方式),或配合自定义 JS 绑定 click(click 方式)
示例关键 CSS:
.dropdown-menu .dropdown-menu {
top: 0;
left: 100%;
margin: 0;
display: none;
}
.dropdown-item:hover .dropdown-menu,
.dropdown-item:focus .dropdown-menu {
display: block;
}
.dropdown-menu.show .dropdown-menu {
display: block;
}
用 Popper.js 手动初始化二级下拉需绕过 Bootstrap 自动绑定
如果要用官方 JS 行为(比如 click 触发、自动关闭、键盘导航),就不能依赖 data-bs-toggle="dropdown" 自动初始化,得手动调用 Dropdown 构造函数,并为每个二级触发项单独实例化。
性能影响不大,但 DOM 结构需严格符合:每个子级 .dropdown 必须是独立包裹容器,不能仅靠 class 堆叠;否则 Popper 定位会错乱。
- 二级菜单的父
<li>必须有class="dropdown",内部包含<a class="dropdown-item dropdown-toggle"></a>和<ul class="dropdown-menu"></ul> - 初始化时需遍历所有
.dropdown-toggle,排除一级的(它们已被 Bootstrap 自动处理),只对[data-bs-toggle="dropdown"][aria-haspopup="true"]中的二级项调用new bootstrap.Dropdown(...) - 注意
boundary配置,避免子菜单被父容器裁剪,建议设为'viewport'
移动端点击穿透和嵌套关闭逻辑容易出错
在触摸设备上,单纯靠 :hover 无法触发二级菜单,必须依赖 click;但 Bootstrap 默认的 click 关闭逻辑会把整个下拉树一起收起,导致点开二级后一级立即关闭。
根本原因是 hidePrevented 事件未被拦截,以及事件冒泡未被阻止。
- 给二级触发链接加
event.stopPropagation(),防止 click 冒泡到一级.dropdown容器 - 监听
hide.bs.dropdown事件,在触发源是子菜单时event.preventDefault() - 移动端还需补充
touchstart代理,否则 iOS Safari 可能无响应
容易被忽略的是:当用户从一级菜单项滑动到二级菜单项时,mouseleave 仍会触发,造成闪退。稳妥做法是加一个 delay: { hide: 200 } 配合 popperConfig 的 modifiers 增加 flip 和 preventOverflow。











