要实现可靠的 scale+fade 过渡,需用 transition 同时控制 opacity 和 transform,显式声明 transform-origin: center,模态框用 position: fixed/absolute,禁用 display: none,改用 visibility+opacity+scale 控制显隐,并分离遮罩层与内容层以兼容 safari 的 backdrop-filter。

直接用 transform: scale() 配合 opacity 做过渡,但必须避开 display: none 和默认 transform-origin 的坑——否则不是闪一下,就是缩放中心偏移、动画“漂”在一边。
为什么 scale 过渡一加就失效或错位?
根本原因是:CSS 不支持单独给 scale 写 transition,你写 transition: scale 0.3s 是无效的;真正要过渡的是 transform 属性本身。而 transform 的缩放原点(transform-origin)默认是 center center,但如果模态框没居中定位、或父容器尺寸不固定,缩放时视觉上就会“跳”。
- 必须显式声明
transform-origin: center(哪怕看起来默认就是它,也得写上) - 模态框容器必须是
position: fixed或absolute,脱离文档流,否则scale会挤压周围元素 - 禁止用
display: none控制显隐——它会让 transition 完全不触发 - 初始状态推荐:
visibility: hidden; opacity: 0; transform: scale(0.9)
怎么写一个靠谱的 scale + fade 过渡?
用单个 transition 声明同时控制 opacity 和 transform,避免不同步。缓动函数别用 ease,它太拖沓;也别用 linear,太机械。真实弹窗需要物理感——快进慢出。
- 推荐写法:
transition: opacity 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94), transform 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94) - 进场类(如
.is-open)设为:visibility: visible; opacity: 1; transform: scale(1) - 别漏掉
visibility: visible——这是触发动画的开关,opacity和transform才是动起来的部分 - 如果缩放后内容模糊(尤其 iOS Safari),加
transform: scale(1) translateZ(0)强制 GPU 加速
移动端滚动穿透和 backdrop-filter 模糊怎么不崩?
iOS Safari 的弹性滚动穿透不是靠 overflow: hidden 能锁住的,而 backdrop-filter 和 transform 同时作用在一个元素上,Safari 会直接禁用模糊效果。
- 遮罩层(
.modal-overlay)和内容层(.modal-content)必须分离:遮罩层只负责backdrop-filter和半透背景,保持静止;缩放只作用于内容层 - 遮罩层样式必须双写:
backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px) - 打开 modal 时,用 JS 记录
window.scrollY,然后给body加style="position: fixed; top: -${scrollY}px;";关闭时恢复并window.scrollTo(0, scrollY) - 别在遮罩层上写
transform或opacity动画——Safari 会直接丢掉模糊
最易被忽略的一点:动画结束帧里不要立刻删类或设 display: none。哪怕只是 visibility: hidden,也要等 transitionend 事件触发后再操作,否则退场动画永远播不完。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











