用 :active 伪类配合 transform 和 opacity 动画可实现不卡、不跳、不残留的点击水滴效果;需用 ::after 伪元素动态定位并设 transform-origin: center,配合 transition 和 pointer-events: none,同时注意移动端适配与 :active 兼容性问题。

直接用 :active 伪类 + transform + opacity 动画就能实现,不需要 JS,也不用 Canvas。关键不是“做出来”,而是“不卡、不跳、不残留”。
为什么不能只靠 :hover 实现点击水滴效果
因为 :hover 是悬停触发,鼠标移开就中断动画;而水滴反馈必须是「点击瞬间触发 → 动画播完 → 自动收尾」,这需要按下(:active)这个瞬态状态来锚定起点。
-
:active在触摸屏上也生效(iOS/Android 都支持),但持续时间极短,必须搭配transition才能延长视觉反馈 - 如果只写
transition: all .3s,会导致按钮所有属性都过渡,比如文字颜色、边框粗细也会“滑动”,干扰焦点 - 某些安卓 WebView 里
:active默认被禁用,需加* { -webkit-tap-highlight-color: transparent; }激活
:active 下如何让水滴从点击点中心扩散
核心是用 ::after 伪元素 + 绝对定位 + transform-origin。不能写死位置,得靠 JS 计算点击坐标——但这里有个取巧办法:把伪元素的 top/left 设为 0,再用 transform: translate(x, y) 动态偏移,配合 transform-origin: center 就能保证缩放始终以中心为原点。
- 必须给按钮设
position: relative,否则::after会相对 body 定位 - 伪元素初始
scale(0)、opacity: 0.6,:active时改为scale(1)、opacity: 0 - 动画用
transition: transform .35s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity .35s,比线性更接近真实水滴张力 - 别忘了加
pointer-events: none到伪元素上,否则它会拦截后续点击
移动端点击区域小、动画易错位怎么办
真机上常出现水滴从左上角炸开,或根本没响应——多半是视口缩放、设备像素比(dpr)没适配,或者 touch-action: manipulation 被误删。
立即学习“前端免费学习笔记(深入)”;
- 确保
<meta name="viewport" content="width=device-width, initial-scale=1">存在且没被覆盖 - 给按钮加
touch-action: manipulation,防止浏览器误判为手势而延迟:active - 如果用了
rem或vw布局,伪元素的width/height必须用固定值(如100px),否则缩放后transform-origin会偏移 - 测试时关掉 Chrome 的 “Emulate touch screen”,真机调试才准——模拟器常忽略
:active的触发时机
最麻烦的其实不是动画本身,而是不同安卓机型对 :active 的触发策略差异:有的要按住 50ms 才触发,有的松手才触发。所以别依赖它做关键业务逻辑,仅作视觉反馈即可。



















