Bootstrap 5 默认不支持多级下拉菜单,需手动实现悬停逻辑、右侧定位、键盘导航及无障碍支持。

Bootstrap 5 默认不支持多级下拉菜单
Bootstrap 5 官方移除了对二级以上下拉菜单(即“下拉里再下拉”)的 CSS 支持和 JS 行为,dropdown-menu 子项里的 dropdown-menu 默认是隐藏且无法触发的。这不是你写错了,是框架故意没做——官方认为多级菜单在移动端体验差、可访问性弱,所以直接砍掉了。
如果你确实需要三级菜单(比如后台系统导航),就得自己补逻辑,不能只靠 data-bs-toggle="dropdown" 堆嵌套。
手动激活二级下拉需监听 mouseenter/mouseleave
Bootstrap 5 的 Dropdown 实例默认只响应一级点击或聚焦,子菜单得靠事件委托 + 手动 show()/hide() 控制。关键不是加更多 data-bs-* 属性,而是接管悬停逻辑。
- 必须给二级
dropdown-menu的父li加class="dropdown-submenu"这类自定义 class,方便选择器定位 - 监听父
li.dropdown-submenu的mouseenter,调用子dropdown的show()方法 - 监听整个
.dropdown-menu的mouseleave,延迟 200ms 再hide(),避免光标经过间隙时闪退 - 移动端仍需保留点击逻辑(
click事件),否则触屏用户点不开
示例片段:
const subMenus = document.querySelectorAll('.dropdown-submenu');
subMenus.forEach(el => {
const subMenu = el.querySelector('.dropdown-menu');
const dropdown = new bootstrap.Dropdown(subMenu);
el.addEventListener('mouseenter', () => dropdown.show());
el.addEventListener('mouseleave', () => setTimeout(() => dropdown.hide(), 200));
});
dropdown-menu 右侧弹出需覆盖 CSS 并修正箭头位置
默认所有 dropdown-menu 都从下方展开,二级菜单想往右贴着显示,光加 data-bs-popper="right" 没用——Bootstrap 5 不认这个属性,且 Popper 配置被封装在 JS 里,不能直接改。
- 必须用 CSS 强制定位:
.dropdown-submenu .dropdown-menu { position: absolute; top: 0; left: 100%; margin-top: -6px; } - 原生下拉箭头(
::before)会错位,得重置:.dropdown-submenu .dropdown-menu::before { display: none; } - 如果父菜单用了
dropend类,它只影响一级,对子菜单无效,别指望靠它自动传导 - 注意 z-index:二级菜单的
z-index必须高于一级,否则被盖住,建议设为1001或更高
键盘导航和屏幕阅读器支持极易被忽略
纯鼠标悬停+手写 JS 的方案,大概率让 Tab 键卡在一级菜单就进不去二级,Esc 也关不掉子菜单——这违反 WCAG 2.1,上线后可能被投诉无障碍问题。
- 必须监听
keydown:在一级菜单项获得焦点时,按→键应展开子菜单并把焦点移到第一个子项 - 子菜单展开后,按
←应收起并返回父项;按Esc应逐级关闭所有打开的子菜单 - 给子菜单的
ul.dropdown-menu加aria-labelledby指向父li的 ID,否则读屏软件不知道这是谁的子集 - 动态增删菜单项时,要重新绑定键盘事件,不能只初始化一次
这事没法靠 CSS 或单个 JS 插件解决,得把键盘流当作核心路径来设计,而不是“有空再补”。


















