必须用JS将点击坐标注入CSS变量并配合radial-gradient与transition实现:监听mousedown获取相对坐标,设为--x/--y,background设circle at var(--x) var(--y),transition控制渐变动画;:active无法传递坐标,纯CSS仅支持固定中心。

按钮点击时波浪纹从点击位置扩散,为什么:active配合radial-gradient能实现
因为:active状态天然捕获鼠标按下瞬间,而radial-gradient的圆心可动态设为calc(var(--x) * 1px) calc(var(--y) * 1px),配合background-position就能让光晕从点击坐标出发。关键不是“用不用”,而是“怎么把坐标传进去”——CSS本身不支持事件坐标绑定,所以必须靠JS注入style属性。
如何用JS把点击坐标写入style并触发radial-gradient动画
直接监听mousedown(不是click),在事件对象里取e.clientX - button.getBoundingClientRect().left和e.clientY - button.getBoundingClientRect().top,然后设置button.style.setProperty('--x', x)和--y。注意:必须用getBoundingClientRect()减去偏移,否则坐标是相对于视口的,会导致波浪错位。
-
radial-gradient背景需设为background-size: 200% 200%,否则默认铺满后无法看到中心扩散效果 - 动画用
transition: background 0.4s ease-out,不能用animation,因为radial-gradient的圆心位置无法被@keyframes驱动 - 按钮
background初始值要设为radial-gradient(circle at var(--x, 50%) var(--y, 50%), rgba(255,255,255,0.3) 0%, transparent 70%),var(--x, 50%)保证未点击时有默认中心点
为什么:active单独用无法实现真实波浪反馈
:active只提供布尔状态,不携带坐标信息。如果只写button:active { background: radial-gradient(circle at 50% 50%, ...); },所有点击都从正中心开始,完全失去“从点击处发散”的交互真实感。更麻烦的是,移动端:active伪类支持不稳定,iOS Safari 默认禁用,必须加* { cursor: pointer; }或touch-action: manipulation才能触发。
- 纯CSS方案(无JS)只能做固定中心的缩放/透明度变化,做不到定位波浪
- 若强行用
transform: scale()模拟波浪,会拉伸整个按钮内容,文字和图标也跟着变形,体验割裂 -
radial-gradient的circle at部分不支持百分比以外的单位(比如px)直接写死,必须靠CSS变量中转
兼容性与性能要注意的三个细节
这个效果在Chrome/Firefox/Edge最新版表现一致,但Safari 15.4之前不支持radial-gradient中使用CSS变量作为位置参数——会直接回退成transparent背景。解决方案是JS检测CSS.supports('background', 'radial-gradient(circle at var(--x) var(--y), #000, #fff)'),不支持时降级为简单opacity变化。
立即学习“前端免费学习笔记(深入)”;
- 频繁点击时,连续触发
mousedown可能造成--x/--y来不及重置,建议加setTimeout(() => { btn.style.removeProperty('--x'); }, 500) - 避免在
body上监听全局mousedown,应绑定到具体按钮,防止干扰其他组件 - 如果按钮有
border-radius,波浪边缘会被裁剪,此时需确保background-clip: padding-box(默认值),不要设成border-box
实际波浪是否自然,取决于transition-timing-function选得准不准——cubic-bezier(0.2, 0.8, 0.2, 1)比ease-out更接近水波衰减感。这点容易被忽略,但改完立刻不一样。


















