应使用 transform: translatex() 而非 left 或 display,因其触发 gpu 加速、不触发重排且不干扰文档流;需显式设置侧边栏宽度以确保位移精准;遮罩须与侧边栏同级并正确设置定位与 z-index;移动端需动态补偿 body 滚动条宽度并禁用 touch-action。

为什么用 transform: translateX() 而不是 left 或 display
直接改 left 会触发重排(reflow),动画卡顿;用 display: none 则根本不会执行 transition,因为元素瞬间被移出渲染树。只有 transform 走合成层、GPU 加速,且不干扰文档流——这是平滑过渡的物理前提。
常见错误是写 transition: all 0.3s,结果其他隐式属性(比如 border-color)偷偷参与过渡,导致节奏错乱。只对明确可控的属性做过渡才稳:
-
transform(必须,驱动位移) -
opacity(可选,配合淡入) -
visibility(仅用于末尾防“幽灵点击”,不能单独过渡)
translateX(-100%) 的宽度基准怎么算
translateX(-100%) 是相对于自身宽度移动,不是视口宽度。如果侧边栏没设固定 width(比如用 width: max-content 或依赖 flex 自适应),位移距离就会不稳定,动画可能“滑过头”或“没推干净”。
实操必须显式定义宽度:
- 给侧边栏设
width: 280px(或min-width+max-width) - 避免用
width: auto或flex: 0 0 auto配合translateX() - 如果内容宽度动态变化(如多语言文案),需在 JS 中读取
offsetWidth后内联设置transform: translateX(-[width]px)
遮罩层(overlay)为什么总点不生效
遮罩失效基本就三类原因:层级错、定位错、事件错。最常犯的是把 <div class="overlay"> 写成侧边栏的子元素,结果被父容器的 <code>overflow: hidden 截断,或者受 flex 布局约束无法铺满全屏。
正确做法:
- 遮罩和侧边栏必须是
下的同级兄弟节点 - 遮罩样式必须含
position: fixed; top: 0; left: 0; width: 100%; height: 100vh; -
z-index:遮罩设999,侧边栏设1000,主内容区保持默认或1 - 遮罩默认加
pointer-events: none,打开时 JS 动态改为pointer-events: auto
移动端滑动穿透和滚动冻结怎么处理
iOS Safari 下,抽屉展开后背景页面仍可滚动,手指一滑就“穿模”;粗暴给 加 overflow: hidden 又会导致页面跳动(滚动条消失 → body 宽度突增)。
可靠解法是组合控制:
- 抽屉打开时:
document.body.style.overflow = 'hidden'+document.body.style.paddingRight = '16px'(补偿滚动条宽度) - 抽屉关闭时:恢复
overflow和paddingRight(别硬写死,要存原始值) - 侧边栏上加
touch-action: none,防止 iOS 滑动冲突 - 键盘用户按
ESC关闭时,焦点必须回到触发按钮,否则 Tab 键会迷失
真正难的不是让抽屉动起来,而是动完之后——焦点在哪、背景能不能点、屏幕阅读器怎么读、低配安卓机会不会闪屏。这些细节漏一处,体验就断一截。











