水波纹效果需用绝对定位伪元素或JS创建的临时节点,锚定点击坐标并以radial-gradient+scale实现扩散动画。关键在动态计算圆心偏移、避免布局干扰、精准监听transitionend、控制并发与性能优化。

水波纹效果的核心是 radial-gradient 动态覆盖
点击时在鼠标位置生成一个从透明到不透明的圆形渐变,再用 transform: scale() 让它向外扩散。关键不是“画个圆”,而是让这个圆始终锚定在点击坐标,且不干扰原有布局——所以得用 position: absolute + pointer-events: none 的伪元素或临时 DOM 节点。
常见错误是直接在目标元素上加 background-image: radial-gradient(...) 并试图动画 background-size,这会导致整个背景重绘、性能差,且无法精确定位圆心。
- 必须用
getBoundingClientRect()算出点击点相对于目标元素左上角的偏移(clientX - rect.left) - 径向渐变的圆心要写成
circle at Xpx Ypx,X/Y 是相对父容器的像素值,不是百分比 - 初始
scale(0)要配合opacity: 0,否则缩放前会闪一下
用 JS 创建水波纹节点比 :hover 伪类更可控
伪类做不到动态定位圆心,也难以控制多个水波纹并发(比如快速连点)。JS 创建临时 注意:不要用 颜色扩散不是靠改渐变色 stops,而是靠同时缩放圆半径和降低透明度衰减速度。典型写法是: 如果只想要单色扩散(比如蓝色变淡),就别写多段 stop,用 Safari 对 解决方案不是砍功能,而是加限制:用节流控制最小间隔(如 实际最难调的是圆心坐标的像素对齐和动画时长匹配: 或 remove()。document.createElement('div') 后 append 到 body,这样会脱离目标元素的定位上下文;应该 append 到目标元素内部,并设 position: relative(如果还没设的话)。
position: relative,否则绝对定位的水波纹会以页面为基准偏移position: absolute; border-radius: 50%; pointer-events: none; z-index: 1
element.addEventListener('transitionend', ...),别用 setTimeout,避免时间不准导致残留节点
radial-gradient 颜色扩散的关键参数组合radial-gradient(circle at Xpx Ypx, transparent 0%, #6366f1 40%, transparent 70%) —— 这里 40% 决定高亮区大小,70% 决定扩散边界,两者差值越大,“晕开”感越强。transparent 0%, #6366f1 30%, transparent 60% 更干净。硬塞 rgba(99, 102, 241, 0.8) 没意义,因为透明度由渐变控制更自然。
transparent,否则圆心会有一块实心点% 表示圆心位置(如 at 50% 50%),那会固定在中心,失去点击定位能力background-size,靠 transform: scale() 控制扩散范围更高效兼容性与性能陷阱:Safari 和低配设备上的表现
radial-gradient 中带变量的 at 位置支持不稳定,尤其当 X/Y 是小数时可能偏移 1px;另外,大量并发水波纹节点(>5 个/秒)在低端安卓机上容易卡顿,因为每个都触发 layout + paint。300ms),并给水波纹加 will-change: transform 提前告知浏览器要动画。但别滥用——只加在真正要动的节点上,否则内存占用飙升。
:active 里用 background 模拟水波纹,iOS Safari 不触发 :active 伪类filter: blur() 做扩散,模糊会严重拖慢渲染帧率scale(3) 配 300ms 看着自然,但若目标元素有 border-radius,水波纹边缘可能被裁切——这时候得把水波纹节点的 overflow: hidden 去掉,或者提前算好最大扩散半径并设 min-width/min-height。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











