涟漪效果的核心原理是通过javascript动态创建圆形span元素,基于点击坐标定位并用transform和opacity实现扩散消散动画。

涟漪效果的核心原理是什么?
涟漪不是纯 CSS 动画能独立完成的,它需要动态生成一个圆形 span 元素,从点击位置(clientX/clientY)出发,以相对按钮左上角为原点进行定位,并用 transform: scale() 和 opacity 实现扩散消散。纯 @keyframes 无法响应点击坐标,所以 JS 是必要环节。
- 涟漪容器必须是
position: relative,否则绝对定位的涟漪会脱离按钮范围 - 每次点击都要新建一个
span.ripple,不能复用,否则多个点击会互相干扰 - 涟漪元素需设
pointer-events: none,避免遮挡后续点击
如何用原生 JS 绑定并计算点击坐标?
关键在 getBoundingClientRect() 和鼠标事件坐标转换:
button.addEventListener('click', function(e) {
const rect = this.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const ripple = document.createElement('span');
ripple.className = 'ripple';
ripple.style.left = `${x}px`;
ripple.style.top = `${y}px`;
this.appendChild(ripple);
// 清理:动画结束后移除 DOM
setTimeout(() => ripple.remove(), 600);
});
-
e.clientX是视口坐标,减去rect.left/top才是相对于按钮的坐标 - 不要用
offsetLeft/offsetTop,它们不包含滚动偏移,容易错位 -
setTimeout时间应与 CSS 动画时长一致(如600ms),否则残留 DOM 节点
CSS 动画部分怎么写才自然?
涟漪的视觉节奏靠两段变化:快速放大 + 缓慢透明消失。推荐用 transform 替代 width/height,性能更好:
用于 inference.sh 的 JavaScript/TypeScript SDK,可运行 AI 应用、构建代理、集成 150+ 模型。包名:@inferencesh/sdk(npm install),完整 TypeScript 支持。
.ripple {
position: absolute;
border-radius: 50%;
background: rgba(0,0,0,0.2);
transform: scale(0);
pointer-events: none;
animation: ripple 600ms linear;
}
<p>@keyframes ripple {
0% { transform: scale(0); opacity: 1; }
100% { transform: scale(4); opacity: 0; }
}</p>
-
scale(4)是经验值,太小看不出扩散,太大可能溢出按钮边界 - 必须设
background且带透明度,纯opacity不够直观 - 不要加
transition,这里用animation更可控
移动端点击无反馈?可能是这个坑
iOS Safari 和部分安卓浏览器默认禁用非可点击元素的 :active 状态,且 click 事件有 300ms 延迟,导致涟漪滞后或不触发:
- 确保按钮有
cursor: pointer和touch-action: manipulation - 添加
ontouchstart="this.click()"或统一监听mousedown/touchstart - 更稳妥做法:把事件监听器绑在
mousedown+touchstart,而非click
涟漪看似简单,但坐标计算、清理时机、移动端适配这三处最容易漏掉,调的时候建议先用 border: 1px solid red 临时标出涟漪位置,确认落点是否准确。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










