侧边滑动导航必须紧邻body,使用fixed定位、transform动画、aria-hidden+inert隐藏语义,配合布尔状态管理、transitionend监听及遮罩层防穿透,确保可访问性与流畅性。

侧边滑动导航的 DOM 结构必须紧邻 <body>
抽屉容器如果嵌在 <header>、<main> 或任意布局 wrapper 里,会因 CSS containment、overflow 截断或 z-index 层级混乱,导致动画卡顿、焦点 trap 失效、屏幕阅读器无法识别。最简且健壮的结构是:
<body>
<nav id="drawer" aria-hidden="true" inert>
<ul><li><a href="/">首页</a></li></ul>
</nav>
<main><!-- 主内容 --></main>
<button id="drawer-toggle" aria-expanded="false" aria-controls="drawer">☰</button>
</body>-
id="drawer"必须唯一,供aria-controls关联按钮 -
aria-hidden="true"+inert是隐藏语义的黄金组合;仅用display: none或visibility: hidden会让键盘和读屏器跳过它 - 不要给
<nav>加tabindex="-1"—— 它本身已是可聚焦元素(有id),加了反而干扰默认焦点流
用 transform: translateX() 而不是 left 或 margin-left
改 left 触发重排,低端安卓 WebView 和 iOS Safari 上常出现闪烁、掉帧甚至动画中断;margin-left 在 flex/grid 布局中行为不可控。只有 transform 走 GPU 合成,顺滑且兼容 IE10+。
- 关键样式必须含:
position: fixed、top: 0、left: 0、width: 280px、height: 100vh - 初始位移写
transform: translateX(-100%)(不是-280px),避免宽度变化时偏移错位 - 过渡只写
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);别用all,也别加opacity过渡——遮罩层穿透点击问题得靠pointer-events: none解决,不是靠透明度 - 务必加
will-change: transform,尤其在 iOS 上能显著减少首帧卡顿
JavaScript 切换状态时必须管理真实开关状态
直接 element.classList.toggle('open') 在快速连点、动画未结束时会翻转两次,导致 DOM class 和视觉状态不一致——比如按钮显示“关闭”,但抽屉其实已收起。
- 用布尔变量记录真实状态:
let isDrawerOpen = false - 点击前先判断:
if (isDrawerOpen) { closeDrawer(); } else { openDrawer(); } - 监听
transitionend事件更新状态,而不是用setTimeout猜时长;注意加event.propertyName === 'transform'过滤,防止其他属性触发误判 - 展开时立即给
<body>加overflow-x: hidden,但别忘了收起后移除——否则页面永远不能横向滚动 - 移动端需额外处理:绑定
touchstart而非click,避开 300ms 延迟;同时保留click兼容桌面
遮罩层和滚动穿透是高频遗漏点
抽屉展开后主内容仍可滚动,松手瞬间 iOS Safari 回弹,用户以为操作失败;遮罩层没阻止点击,导致点透到背后按钮上——这两个问题几乎 100% 出现在初版实现中。
立即学习“前端免费学习笔记(深入)”;
- 遮罩层必须是独立
<div id="drawer-backdrop">,紧跟<nav id="drawer">后,z-index 比抽屉低一级,但高于主内容 - 遮罩层样式:
position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.5); pointer-events: auto; - 滚动冻结不能只靠
body { overflow: hidden };iOS 需配合document.body.style.position = 'fixed'+ 记录当前scrollY,收起时再还原 - 所有交互入口(按钮、遮罩、ESC 键)都要调用同一套开关函数,避免状态分支
抽屉导航真正难的不是滑动动画,而是状态同步、可访问性控制与滚动行为的耦合。哪怕只漏掉 inert 或 transitionend 监听,都会在特定设备上暴露交互断裂。



















