transform+transition首次无动画因none不可插值,须显式设初始transform值并写在基础class中;禁用display:none;移动端需passive:false、getBoundingClientRect基准位移、will-change动态启用及cubic-bezier回弹。

直接用 transform: translateX() 配 transition 就能实现平滑滑动,但第一次没动画、点击后闪一下、移动端拖不动——这些问题基本都出在初始值、触发时机或交互隔离上。
为什么 transform + transition 第一次没动画
浏览器不会对从 none 到 translateX(0) 做插值,因为 none 不是可计算值。必须显式写死起始态。
-
transform初始值不能省略,比如写成transform: translateX(-100%);,而不是依赖默认的none -
transition必须写在基础 class 里(如.sidebar),不能只写在.sidebar.open中 - 别用
display: none控制显隐——它会让元素脱离渲染树,transform和transition全部失效 - 如果 JS 动态加 class 后立刻读取
offsetWidth或getComputedStyle(el).transform,会强制同步布局,打断动画帧
移动端点击后侧边栏闪一下才展开?检查 pointer-events
用 pointer-events: none 隐藏侧边栏时,切到 pointer-events: auto 的瞬间,事件捕获和 layout 不同步,容易导致点击穿透或重绘抖动。
- 改用
visibility: hidden+opacity: 0组合,并配transition: visibility 0s 0.3s, opacity 0.3s实现延迟隐藏 - 更稳妥的做法是保持
visibility: visible,仅靠transform: translateX(-100%)移出视口,让元素始终参与事件流和布局计算 - 遮罩层(
.overlay)必须设pointer-events: auto,且z-index高于主内容;侧边栏内容区则设pointer-events: none,按钮等可点元素再单独开pointer-events: auto
touch 拖拽不生效或回弹卡顿?passive 和 will-change 得配对用
iOS Safari 和部分安卓 WebView 对 touch 事件默认启用 passive: true,一旦你调了 preventDefault()(比如阻止页面滚动),事件就会被静默忽略。
立即学习“前端免费学习笔记(深入)”;
- 绑定
touchstart时必须传{ passive: false },且只对真正需要拦截滚动的元素加 - 位移计算别用
clientX差值——缩放、快速滑动下误差大;应基于getBoundingClientRect().left做基准,每次touchmove叠加 Δx 更新transform - 拖拽中动态加
style="will-change: transform;",拖完立刻移除;别和transform: translateZ(0)叠加用,否则可能触发重绘 - 回弹动画推荐用
cubic-bezier(0.25, 0.46, 0.45, 0.94),比ease更符合物理惯性
侧边栏打开时背景还能滚动?overflow: hidden 在 Safari 下要补 position: fixed
只给 body 加 overflow: hidden 在 iOS Safari 里经常无效,手指一划还是能滚。
- 必须同时加
position: fixed; top: 0;到body,才能真正锁住滚动 - 记得在关闭侧边栏时还原
body的position和overflow,否则页面会“失焦”或错位 - 如果侧边栏高度超长,内部滚动需单独设
overflow-y: auto和height: calc(100vh - 64px)(减去 header 高度) - 别用
left动画替代translateX——高 DPI 屏或缩放页面时偏移不准,transform才是硬件加速的可靠路径
最常被忽略的一点:侧边栏的 box-sizing 必须是 border-box,哪怕只加了 1px border,没设这个也会让 width: 240px + padding: 12px 实际撑到 264px,导致 translateX(-100%) 移不全、边缘露白。


















