:active伪类仅在鼠标按下或触摸期间生效,松开即结束,无法直接驱动@keyframes动画;需配合transition实现收缩回弹效果,且须满足移动端激活条件(如cursor: pointer、onclick等)才能生效。

button的:active为什么点不动?
因为:active只在鼠标按下/触摸期间生效,松开就立刻结束,没法直接触发@keyframes动画——浏览器不会等你写完动画再释放状态。常见现象是:写了transform: scale(0.95)在:active里,但看起来像“没反应”或“闪一下就没了”,其实是动效太短、没加过渡,或者被其他样式覆盖了。
真正能用:active做的,只有瞬时反馈(比如颜色变深、边框微缩),不能靠它驱动完整“收缩→回弹”流程。想实现回弹,必须用transition配合初始态和激活态的平滑插值。
- 确保
button有transition声明,且作用于transform或scale相关属性 -
:active里只改可过渡的属性值(如transform: scale(0.92)),别写display: none或visibility: hidden这类不可过渡的 - 移动端要注意
:active默认不触发,得加cursor: pointer或tapping-enabled相关meta
用transition模拟收缩回弹的关键参数
核心不是写多复杂的动画,而是控制好“按下时缩”和“松开时自动弹回”的节奏。这完全依赖transition的起始值、终点值和缓动函数。
示例代码:
立即学习“前端免费学习笔记(深入)”;
button {
transform: scale(1);
transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
}
button:active {
transform: scale(0.94);
}
-
transition必须写在常态(非:active)规则里,否则松开时没过渡 - 时间选
0.16s–0.22s最接近真实按钮手感;太长像卡顿,太短像没动 -
cubic-bezier(0.4, 0, 0.2, 1)比ease-out更自然:先快缩,后慢回,避免生硬弹跳 - 别用
all做transition-property,会意外触发文字模糊、阴影跳变等问题
为什么加will-change: transform有时反而更卡?
这个属性本意是提示浏览器“这个元素要频繁变换”,让其提前进图层合成。但滥用会导致内存占用升高、滚动掉帧,尤其在低端安卓机上。
- 只在明确观察到点击卡顿(比如连续快速点同一按钮)时才加,不是标配
- 加的位置是常态规则,不是
:active里:button { will-change: transform; } - 用完记得监控FPS,如果
transform本身很简单(比如就一个scale),大概率不需要它 - 真要优化,优先检查有没有其他JS监听了
click或touchstart并做了重排重绘
移动端:active失效的三个硬性条件
iOS Safari 和部分安卓WebView 默认禁用:active伪类,除非满足以下任一条件:
- 元素绑定
onclick空事件:<button onclick="void 0"></button> - 父容器设了
cursor: pointer(哪怕只是html或body) - 页面
里有<meta name="viewport" content="width=device-width, user-scalable=no">(注意user-scalable=no会禁用双指缩放,慎用)
最稳妥的做法是同时满足前两项:给button加cursor: pointer,再确保它是个可点击语义元素(<button></button>或带role="button"的<div>)。
<p>复杂点在于,有些UI库(比如早期Ant Design Mobile)会把<code>button渲染成<div>,这时<code>:active根本不会触发——得手动加ontouchstart="void 0"或用pointer-events: auto兜底。










