Bootstrap 5 官方不支持多级下拉菜单,因其Dropdown插件仅监听一级.dropdown-item的事件,嵌套的.dropdown-menu既无JS事件注册也无CSS定位规则,需手动补悬停逻辑、右侧定位、键盘导航及无障碍支持。

Bootstrap 5 官方不支持多级下拉菜单,所谓“制作”不是启用某个开关,而是绕过框架限制、手动补逻辑——否则在桌面端悬停无反应、移动端点不开、键盘无法导航、屏幕阅读器直接跳过子菜单。
为什么纯 data-bs-toggle="dropdown" 嵌套会失效
Bootstrap 5 的 Dropdown 插件只监听一级 .dropdown-item 的 click/focus,对嵌套在 .dropdown-menu 内的第二个 .dropdown-menu 完全无视。你加再多层 data-bs-toggle="dropdown" 都不会触发 show/hide,因为 JS 没注册它的事件监听器。
- HTML 结构合法(
<ul class="dropdown-menu"><li><ul class="dropdown-menu">...</ul></li></ul>),但 CSS 默认把它压成display: none且无过渡控制 -
.dropdown-menu .dropdown-menu没有默认定位规则,会叠在父菜单下方,而不是向右展开 - 所有子菜单共享同一层 z-index 上下文,容易被
.navbar或.modal盖住
纯 CSS hover 方案:只适用于桌面端,且必须修正定位
用 :hover 触发二级显示最轻量,但仅限鼠标设备;iOS/Android 上基本不可用,且焦点导航(Tab 键)完全失效。
- 父级
.dropdown-item必须设position: relative,否则left: 100%会相对 body 定位 - 二级菜单要写成
.dropdown-item:hover > .dropdown-menu,不能写成.dropdown-menu:hover .dropdown-menu(后者永远不匹配) - 必须覆盖默认 opacity/visibility 动画:
.dropdown-menu .dropdown-menu { display: none; }+.dropdown-item:hover > .dropdown-menu { display: block; } - 右侧展开需加:
.dropdown-menu .dropdown-menu { position: absolute; top: 0; left: 100%; margin-top: -6px; z-index: 1001; }
JS 手动接管:支持键盘、移动端点击、无障碍,但代码量明显增加
不能依赖 new bootstrap.Dropdown() 直接套娃,得用事件委托 + 显式调用 show()/hide(),并处理延迟隐藏、ESC 关闭、Tab 键流转等细节。
- 给二级父项加自定义类,比如
class="dropdown-submenu",方便选择器定位 - 监听
mouseenter时调用子菜单的show(),监听整个.dropdown-menu的mouseleave并setTimeout(..., 200)后hide(),避免光标经过间隙闪退 - 移动端仍需绑定
click事件(e.preventDefault()阻止默认跳转),否则触屏用户点一次就走了 - 必须手动处理键盘:
ArrowRight进入子菜单、Escape逐级退出、Tab在子菜单项间流转——否则 WCAG 2.1 直接不达标
响应式侧边栏多级菜单:别用 collapse 套娃
把多个 .collapse 套在同一个 data-bs-target 下,点开一级就会连带展开所有子级,根本没法独立控制收放状态。
- 移动端(
max-width: 768px)必须强制收起全部子菜单,否则侧边栏撑出视口 - 桌面端建议只展开当前激活路径的祖先节点,而非全部展开——信息密度和首屏加载都受影响
- 每个子菜单需独立维护
is-open状态,用data-bs-target="#submenu-1"+ 手动bootstrap.Collapse实例控制 - 注意
.navbar-collapse有transform,会创建新层叠上下文,子菜单z-index再高也无效,得把子菜单 DOM 提升到同级容器中
最易被忽略的是键盘与屏幕阅读器支持——90% 的手写 JS 多级菜单方案会让 Tab 键卡死在一级,或者 ESC 关不掉子菜单。这不是“能用就行”的问题,是上线后可能被投诉合规风险的实际障碍。


















