q弹效果关键在缓动函数与变形节奏:需下压→回弹→微晃三段物理感,单用scale(0.95)+ease不够;应分开控制scale与translatey,避免渲染错乱;推荐cubic-bezier(0.3,1.2,0.5,1)实现过冲回弹;移动端需语义化标签、cursor:pointer及避免preventdefault。

直接用 :active 配合 transform: scale() 和 transition 就能做出基础Q弹效果,但真正“弹”得自然、不僵硬,关键在缓动函数和变形节奏的控制——不是越快越弹,而是要有下压→回弹→微晃的物理感。
为什么单纯 scale(0.95) + transition 不够弹?
因为线性或 ease 缓动无法模拟弹性回弹。人眼对“按下去立刻弹回来”有预期,但纯 CSS 默认过渡是匀速或缓入缓出,缺乏二次反弹和停顿感。
-
transition: transform 0.2s ease看起来像“缩一下就停”,不是“压下去、弹上来、再晃一下” - 真实Q弹需要至少两段节奏:快速下压(
ease-out),然后带回弹的上升(cubic-bezier(0.2, 0.8, 0.4, 1)) - 如果只写一个
transition值,所有 transform 变化(scale + translateY)会共用同一缓动,容易打架
:active 中如何组合 scale 和 translateY 才不翻车?
必须分开控制位移和缩放,否则 transform: scale(0.95) translateY(2px) 在低版本 Safari 里可能渲染错乱或抖动。
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
- 写成
transform: scale(0.95) translateY(2px)是安全的,但要确保父容器没设will-change: transform——它会提前触发合成层,反而让小位移卡顿 - 更稳妥的做法是只用
scaleY(0.92)模拟“被压扁”,配合box-shadow收缩,视觉欺骗更强 - 别在
:active里加rotate(),除非图标本身对称;非对称图标(如箭头、播放按钮)一旋转就偏移中心,显得失控
想加二次微弹怎么办?不能用 JS 就只能靠 animation?
可以,但别用 @keyframes + animation 绑定到 :active——大多数浏览器不支持伪类触发 animation,且移动端 :active 生命周期太短,动画刚播一半就结束了。
- 真正可行的是:用
:active触发一个极短的transition,再靠cubic-bezier(0.3, 1.2, 0.5, 1)实现“过冲回弹”效果 - 例如:
transition: transform 0.25s cubic-bezier(0.3, 1.2, 0.5, 1),这个贝塞尔曲线会让 scale 先冲过 1.0 再回落,形成微晃 - 如果非要动画帧控制,得降级为 class 切换(比如监听
touchstart加is-pressed类),但这就脱离了纯 CSS 范畴
移动端点击无反馈?别怪 :active 失效,先查这三件事
iOS Safari 和部分安卓 WebView 对 :active 的支持非常苛刻,不是写错了,而是环境没配对。
- 元素必须是可聚焦/可点击语义化标签:
<button></button>或带role="button"的<div>,纯 <code><span></span>基本无效 - 加
cursor: pointer或touch-action: manipulation才能唤醒点击态,尤其 iOS 17+ 默认禁用非交互元素的:active - 别在 JS 里对这个元素调用
event.preventDefault(),哪怕只是想阻止默认跳转——它会直接掐断:active的样式生命周期
最难调的其实是“弹多少”:scale 减 0.03 看不出,减 0.1 又像故障;真实项目里建议从 scaleY(0.97) 开始试,在真机上连点十次,看手指反馈和视觉反馈是否同步——这才是 Q 弹的临界点,不是参数表里能抄来的。










