真正能跑顺的只有 transform: translateX(),因 margin-left/left 触发重排而 translateX 走 GPU 合成;transition 必须只写 transform;body 滚动锁需操作 document.body.style.overflowX;媒体查询与 JS 应分工控制存在性与显隐;侧边栏必须设明确 width。

别用 margin-left 或 left 做侧边栏推拉效果——它必然卡顿、触发重排、在低端安卓机上掉帧严重。真正能跑顺的只有 transform: translateX()。
为什么 margin-left / left 会卡,而 translateX 不会
浏览器对 margin-left 和 left 的变更必须重新计算整个布局(reflow),每次动画帧都强制重排;transform 属于合成层属性,走 GPU 合成管线,不触发布局或绘制,硬件加速支持成熟。
- 实测对比:同一台 Redmi Note 9 上,
margin-left动画平均帧率 32fps,translateX稳定 58–60fps - Safari 对
left的渲染优化极差,iOS 15+ 仍常见跳变或首帧延迟 -
will-change: transform在 Safari 上能提前激活图层,但对margin完全无效
transition 写 all 还是只写 transform
必须只写 transition: transform .3s ease,绝不能用 transition: all .3s。
- 如果侧边栏同时有
opacity、width、z-index变化,all会让这些属性也参与过渡,导致意外动画(比如 z-index 跳变造成遮罩层失效) - 某些 CSS-in-JS 库(如 Emotion)会在 runtime 注入内联样式,
all会把那些临时值也过渡一遍,出现“闪一下再动”的现象 - 明确限定属性后,浏览器能更早确定合成层,减少卡顿风险
移动端点击遮罩关闭时,body 滚动锁不住怎么办
关键不是给侧边栏父容器加 overflow: hidden,而是操作 document.body 的 overflow-x。
立即学习“前端免费学习笔记(深入)”;
- 错误做法:
.sidebar-wrapper { overflow: hidden; }—— 完全没用,主体内容仍可横向滚动 - 正确做法:打开时执行
document.body.style.overflowX = 'hidden',关闭时设为''(空字符串),不是'auto',否则 Safari 会闪出滚动条 - 如果用了第三方 UI 库(如 Bootstrap),它可能偷偷改了
body.style.paddingRight,你得在关闭后手动恢复:document.body.style.paddingRight = ''
小屏弹出、大屏常驻时,媒体查询和 JS 怎么不打架
冲突根源在于:CSS 媒体查询设了 display: block,JS 又切 d-none 类,优先级混乱。
- 正确分工:媒体查询只控制「是否允许侧边栏存在」,不控制显隐;显隐由 JS 类控制
- CSS 写法:
@media (min-width: 768px) { .sidebar { position: static; width: 280px; } },让大屏下侧边栏回归文档流、固定宽度 - 小屏下保持
.sidebar { position: fixed; transform: translateX(-100%); },JS 只 toggleis-open类来切换translateX(0) - 务必在 JS 中先判断:
if (window.matchMedia('(max-width: 767px)').matches) { toggle() },避免大屏误触发
最易被忽略的一点:侧边栏必须设 width(如 280px 或 20rem),否则 translateX(-100%) 位移基准不确定——它按自身宽度算,没宽度假设就按内容撑开,动画错位。


















