抽屉菜单必须用 transform: translateX() 实现,禁用 left/top;显隐用 visibility+transform 控制,禁用 display 切换;过渡曲线推荐 cubic-bezier(0.34, 1.56, 0.64, 1);打开时需保存并还原 scrollY 防 iOS 滚动重置;折叠菜单 max-height 不可用 auto,须设具体值并配 overflow: hidden。

抽屉菜单必须用 transform,别碰 left 或 top
直接改 left 或 top 会强制浏览器重排,动画卡顿明显,尤其在 iOS Safari 上一滑就掉帧。唯一可靠路径是 transform: translateX() —— GPU 加速、不打断渲染流水线。
常见错误是把抽屉设成 display: none 再切回 block,这会让 transition 完全失效(浏览器跳过过渡过程)。正确做法是始终保留在 DOM 中,仅靠 transform 和 visibility 控制显隐:
-
visibility: hidden; transform: translateX(-100%);→ 完全隐藏且不占位 -
visibility: visible; transform: translateX(0);→ 滑入可视区 - 过渡只加在
transform上,visibility不参与transition(它本身不可过渡)
transition-timing-function 别用默认 ease
默认 ease 太“软”,抽屉像被橡皮筋拉出来;ease-out 开头太快,缺乏启动感。真正顺滑的抽屉需要“慢进快出”:起始有缓冲,结束有惯性收尾。
推荐用 cubic-bezier(0.34, 1.56, 0.64, 1) —— 这是 Material Design Drawer 官方用的曲线,能模拟物理滑动的加速度变化。实测比 ease-in-out 更自然,尤其在快速连续开关时不易产生“粘滞感”。
立即学习“前端免费学习笔记(深入)”;
注意:cubic-bezier(0.34, 1.56, 0.64, 1) 在 Safari 旧版本(如 iOS 12 以下)可能解析异常,需降级为 ease-out 并加 will-change: transform 保帧率。
抽屉打开时,背景内容不能滚动
不能只靠给 body 加 overflow: hidden —— iOS Safari 会把滚动位置重置到顶部,键盘弹起后也无法恢复。
可行方案是:抽屉打开时,给 body 加 position: fixed; top: -${window.scrollY}px;,并记录原始 scrollY;关闭时还原 body 样式,并执行 window.scrollTo(0, savedScrollY)。
更轻量的做法是监听抽屉状态,在打开时给 body 加 class(如 drawer-open),再配合 CSS:
body.drawer-open {
position: fixed;
width: 100%;
top: calc(var(--scroll-y, 0px) * -1);
}然后用 JS 动态写入 --scroll-y 自定义属性。
折叠菜单用 max-height 时,auto 是无效值
max-height: 0 → auto 不会触发过渡动画——auto 不是可计算数值,浏览器不知道该插值到哪。常见现象是菜单“啪”一下弹出或消失。
必须用具体像素值替代 auto,例如 max-height: 400px 或 max-height: 30em:
- 值要足够大,确保所有内容完全可见
- 但也不能过大,否则收起时动画结束仍留白
- 若内容高度动态变化(如文字长度不一),纯 CSS 就不够用了,得靠 JS 读取
scrollHeight后写入max-height
记得始终配 overflow: hidden,漏掉它,内容会在动画中溢出、遮挡其他元素。


















