translateX()是唯一靠谱的选择,因其走GPU合成层、只重绘不重排,可稳住60fps;而left或margin-left会触发重排导致卡顿闪动,iOS还会警告降级。

必须用 transform: translateX(),其他方案在真机上基本会卡顿或闪动。
为什么 translateX() 是唯一靠谱的选择
改 left 或 margin-left 会触发浏览器重排(reflow),动画一跑就掉帧;低端安卓机常卡在 30fps 以下,iOS Safari 还会弹黄色警告“强制降级”。translateX() 走 GPU 合成层,只重绘不重排,是目前唯一能稳住 60fps 的方案。
常见错误现象包括:left: -100% 在 iOS 上收起时闪一下才消失、点击后抽屉“顿半拍”才动、快速连点两次位移错乱。
-
translateX(-100%)是相对自身宽度的位移,适配不同设备更稳妥;但如果侧边栏宽度固定(如width: 280px),直接写translateX(-280px)更精准,避免视口缩放导致偏移不准 - 千万别同时写
left和transform:浏览器合并计算行为不可控,Safari 可能直接忽略translateX() -
translate(-200px)缺少轴向标识,可能被解析为 X+Y 位移;translateX(-200)漏单位则无效
transition 必须写对位置和参数
transition 必须声明在侧边栏元素的基础 CSS 规则里,不能只写在 .sidebar--open 类中,也不能写在按钮或父容器上——否则 class 切换时动画根本不会触发,变成“瞬移”。
立即学习“前端免费学习笔记(深入)”;
- 推荐写法:
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);—— y1 > 1 才有弹性超调感,收尾带缓冲,比默认ease更自然 - 别写
transition: all 0.3s:后续加了color或opacity就会意外带出其他动画 - 初始状态不能用
display: none或visibility: hidden:这会让transform和transition全部失效
定位、合成层与遮罩层缺一不可
只写 transform 和 transition 还是会抖、有白边、iOS 上被截断,是因为没触发独立合成层。浏览器默认把元素画在主渲染层,动画时仍可能牵扯 layout 或 paint。
- 必须三件套齐上:
position: fixed(或absolute)、will-change: transform(仅在 JS 打开/关闭前瞬间设,结束后立刻还原为auto)、backface-visibility: hidden(iOS Safari 必加,否则拉出一半常出现白边) - 遮罩层
.overlay必须position: fixed; width: 100vw; height: 100vh;(别用100%,某些安卓浏览器算的是父容器高度) - 层级顺序要严格:
z-index主内容区为 1、遮罩层为 10、侧边栏为 11;否则 iOS 上touchstart可能穿透到下层
JS 控制显隐必须用 class 切换,不是内联样式
别在 JS 里写 el.style.transform = 'translateX(0)' —— 这会覆盖 CSS 中定义的 transition,首次展开没动画;也容易和 rotate/scale 等其他 transform 值冲突。
- 正确做法是纯 class 控制:CSS 定义
.sidebar--closed { transform: translateX(-100%); }和.sidebar--open { transform: translateX(0); } - JS 用
sidebarEl.classList.toggle('sidebar--open')切换;点蒙层关闭时用classList.remove(),不是toggle(),避免误触二次展开 - 滚动锁定必须加在
body上:.no-scroll { overflow: hidden; height: 100vh; overscroll-behavior: contain; },JS 打开时加,关闭时立刻移除(别等transition结束)
最麻烦的其实是拖拽松手那一刻的边界判断——位移阈值、速度,还有是否该回弹,这些逻辑一旦写错,用户就会觉得“不跟手”或“关不严”。


















