纯CSS无法实现真实点击位置出发的波纹效果——:active无坐标信息、@keyframes无法读取clientX/clientY,且:active状态松手即失效,动画无法播完;必须用JS动态计算坐标并驱动::after伪元素。

纯 CSS 无法实现悬浮按钮点击时从真实点击位置出发的波纹扩散效果——:active 没有坐标信息,@keyframes 无法读取 clientX/clientY,所有“纯 CSS”方案都只能固定从中心或左上角触发。必须用 JavaScript 动态计算并驱动 ::after 伪元素。
为什么不能只靠 :hover + :active + transition
因为 :active 是瞬时状态,松手即失效(通常 :active,即使强制启用,left/top 也写死无法动态更新。结果就是:点哪都从中心炸、快速连点堆满残留、真机上一闪就消失。
::after 伪元素必须配合 JS 定位和清理
核心是让 ::after 承载波纹:不占 DOM、支持硬件加速的 transform: scale()、能设 pointer-events: none 避免拦截后续点击。
- 按钮必须设
position: relative,否则::after会相对于body定位,导致波纹从页面左上角炸开 -
::after要设content: ""、position: absolute、border-radius: 50%、z-index: -1、pointer-events: none - JS 中用
e.clientX - button.getBoundingClientRect().left算出相对 X,同理算 Y;再通过style.setProperty('--x', x + 'px')注入 CSS 变量(别用style.left,Safari 不支持内联定位) - 每次点击前先清旧值:
button.style.setProperty('--x', '0px'),否则新波纹从上一次位置起始 - 动画结束必须监听
animationend并调用element.remove(),不能靠setTimeout,否则真机残留
移动端和 Safari 的硬坑怎么绕
iOS Safari(尤其 15.4 以下)对 ::after + transform: scale() 有重绘 bug:卡顿、闪烁、甚至不触发。这不是加 -webkit- 前缀能解决的。
立即学习“前端免费学习笔记(深入)”;
- 给
::after动态加will-change: transform(JS 点击时才 set,别写在常态 CSS 里) - 移动端必须监听
touchstart,取e.touches[0].clientX;click在 iOS 上有 300ms 延迟且坐标不准 - 父按钮加
overflow: hidden,否则波纹放大后会撑出圆角边界,Safari 会裁切动画轨迹 - 圆心定位统一用
transform: translate(x, y) scale(s),别混用top/left—— Safari 对混合定位合成不稳定
真正难的从来不是写那几行 @keyframes,而是坐标计算是否扣准滚动偏移、伪元素是否被正确复用、动画结束是否被可靠监听——这些细节在真机上一错就全崩。


















