应使用 Bootstrap 5.2+ 的 offcanvas 组件实现原生、轻量侧边菜单,因其内置响应式隐藏、多方向滑出、遮罩、ESC关闭及无障碍支持;须将 offcanvas 置于 body 直接子级,配 data-bs-toggle/data-bs-target,添加 aria-controls 和 aria-labelledby 保障可访问性,并通过 CSS 变量或自定义类控制断点与宽度。

用 offcanvas 组件实现原生、轻量的侧边菜单
Bootstrap 5.2+ 内置了 offcanvas,不用额外 JS 或第三方库就能做手机端抽屉菜单。它默认响应式隐藏,触发后从左/右滑出,动画流畅且语义清晰。比自己写 transform: translateX() 更可靠,也比依赖 collapse + 手动控制宽度更符合移动端交互直觉。
关键点:
-
offcanvas必须放在直接子级,否则 backdrop 遮罩层可能错位或不触发关闭 - 默认从左侧展开,加
class="offcanvas-end"可改为右侧;加class="offcanvas-bottom"是底部弹出(适合操作面板,非典型侧边菜单) - 必须手动添加
data-bs-toggle="offcanvas"和对应href或data-bs-target,Bootstrap 不会自动绑定按钮和菜单
HTML 结构要满足 ARIA 可访问性要求
单纯能动不算完成——屏幕阅读器用户需要明确知道菜单状态、角色和控制方式。Bootstrap 的 offcanvas 默认已含 role="dialog" 和 aria-modal="true",但你得补全两处:
- 触发按钮必须有
aria-controls="your-offcanvas-id",指向菜单容器 ID - 菜单容器需有
aria-labelledby指向其标题元素 ID(例如<h5 id="offcanvasLabel">菜单</h5>) - 如果菜单里有链接,建议用
<nav></nav>包裹,并加aria-label="主菜单"
漏掉这些,offcanvas 虽然视觉上工作正常,但 WCAG 2.1 AA 级别会失败。
自定义宽度和断点容易踩的坑
默认 offcanvas 在 md(768px)以上就自动隐藏,变成“常驻”状态——这不符合“手机端抽屉”的本意。你需要覆盖它的媒体查询逻辑:
- 不要直接改 Bootstrap CSS 文件,而是用自定义类,比如
offcanvas-sm,并在 CSS 中重写@media (min-width: 576px)下的display: none - 调整宽度时,别只改
width,还要同步修改max-width和transform的临界值(如translateX(-100%)→translateX(-300px)),否则动画偏移错位 - 若需固定宽度(如 280px),推荐用
style="--bs-offcanvas-width: 280px;",这是 Bootstrap 5.3+ 提供的 CSS 变量接口,比覆盖 class 更干净
关闭后焦点未回传到触发按钮的问题
用户点击菜单内链接跳转,或按 Esc 关闭后,焦点常丢失在 body 上,导致键盘用户必须 Tab 很多次才能回到顶部导航。这不是 Bug,是默认行为缺失。
解决方法很简单,在初始化后手动监听 hidden.bs.offcanvas 事件:
const myOffcanvas = document.getElementById('mobileMenu')
myOffcanvas.addEventListener('hidden.bs.offcanvas', () => {
document.getElementById('menuToggleBtn').focus()
})
注意:这个按钮必须是可聚焦元素(button 或带 tabindex="0" 的元素),且不能被 display: none 隐藏。
真机测试时最容易忽略的是 backdrop 点击穿透——如果菜单里用了 position: fixed 的下拉或浮层,它们可能盖在 backdrop 上,导致点不到遮罩关闭菜单。这时候要么提升 z-index,要么改用 position: absolute 配合父容器 overflow 控制。


















