Drawer动画必须用transform+transition而非left/top,因其触发GPU加速、避免重排卡顿;初始设translateX(-100%)、visibility:hidden、opacity:0,开启时切至translateX(0)、visible、opacity:1,并配精准transition声明。

Drawer动画必须用transform + transition,别碰left/top
直接改left或top会触发重排,动画卡顿明显,尤其在移动端。用transform: translateX()是唯一靠谱选择——GPU加速、不打断渲染流水线。
常见错误是给drawer设display: none再切回block,这会导致transition完全失效(浏览器跳过过渡过程)。正确做法是始终保留元素在DOM中,仅靠transform和visibility控制显隐:
-
visibility: hidden+transform: translateX(-100%)→ 完全隐藏且不占位 -
visibility: visible+transform: translateX(0)→ 滑入可视区 - 过渡只加在
transform上,visibility不参与transition(它本身不可过渡)
transition-timing-function选ease-out还是cubic-bezier(0.34, 1.56, 0.64, 1)?
默认ease太“软”,抽屉像被橡皮筋拉出来;ease-out开头太快,缺乏启动感。真正顺滑的抽屉动画需要“慢进快出”:起始有缓冲,结束有惯性收尾。
推荐用cubic-bezier(0.34, 1.56, 0.64, 1)——这是Material Design Drawer官方用的曲线,能模拟物理滑动的加速度变化。实测比ease-in-out更自然,尤其在快速连续开关时不易产生“粘滞感”。
立即学习“前端免费学习笔记(深入)”;
注意:这个贝塞尔值在Safari旧版本可能解析异常,如需兼容iOS 12以下,降级为ease-out并加will-change: transform保帧率。
如何阻止背景内容滚动而抽屉开着?
Drawer弹出时,用户如果滚动页面,背景会动,但抽屉不动,视觉割裂感极强。不能只靠overflow: hidden在body上——iOS Safari会把滚动位置重置到顶部,而且键盘弹起后无法恢复。
更稳的方案是:在drawer打开时,记录当前document.documentElement.scrollTop,然后给body加position: fixed + top: -scrollTop,同时设width: 100%防横向偏移:
body.drawer-open {
position: fixed;
top: -123px; /* 当前滚动Y值 */
width: 100%;
overflow-y: hidden;
}关闭时还原body样式,并用setTimeout(() => window.scrollTo(0, scrollTop), 0)延迟恢复滚动位置(避免iOS强制跳顶)。
点击遮罩层关闭Drawer时,如何避免误触内部链接?
遮罩层.drawer-overlay通常覆盖整个视口,z-index高于drawer内容。但如果drawer里有按钮或链接,手指划过遮罩层关掉Drawer的同时,可能刚好点中下层未销毁的按钮——尤其是React/Vue组件未及时v-if或ngIf销毁时。
解决方法分两层:
- 结构上:确保遮罩层DOM顺序在drawer内容之后,即
<div class="drawer">...</div><div class="drawer-overlay"></div>,而非包裹关系 - 交互上:遮罩层
click事件里调用event.stopPropagation(),同时给drawer容器加pointer-events: auto(遮罩层默认pointer-events: auto,但父容器若设了none会拦截) - 额外保险:关闭Drawer后,用
setTimeout(() => drawerEl.focus(), 0)把焦点移回触发按钮,避免键盘用户迷失
动画结束时机比想象中更关键:别在transitionend里立刻销毁DOM,先等getComputedStyle(drawerEl).transform确认已回到translateX(-100%),再清理——某些安卓WebView里transitionend会提前触发。


















