波纹效果需父容器设 position: relative,用 getBoundingClientRect() 精准定位圆心,动画用 transform: scale() 避免重排,移动端应监听 pointerdown 事件。
波纹效果本质是用 position: relative 作为容器,再动态插入绝对定位的 span 圆形元素。如果父容器是默认的 static 定位,波纹会脱离点击位置,飞到页面左上角。
<button> 或 <div class="ripple">)加上 position: relative
.btn 等类重置了定位 —— 建议显式覆盖:.btn { position: relative !important; }
getBoundingClientRect() 是定位波纹中心的关键靠 event.clientX / clientY 算坐标在滚动页面时会偏移,必须用 element.getBoundingClientRect() 获取元素视口内位置,再减去元素左上角偏移,才能精准定位圆心。
const x = e.clientX - e.target.offsetLeft(滚动时错)const rect = e.target.getBoundingClientRect();<br>const x = e.clientX - rect.left;<br>const y = e.clientY - rect.top;
rect 返回的是浮点数,但 CSS left/top 支持小数,无需 Math.round(),反而会抖动transform: scale() 而非 width/height
直接改 width 和 height 触发 layout,帧率掉得厉害;用 transform: scale() 只走合成层,60fps 更稳,尤其在低端安卓机上。
transform: scale(0) 和 transform-origin: center
setTimeout 清除 DOM,否则大量点击后内存泄漏:setTimeout(() => ripple.remove(), 500)(500ms 对应 CSS 动画时长)transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.2, 1),比 ease-out 更自然touchstart
在 iOS 和部分安卓浏览器里,click 触发太慢,波纹响应滞后明显。必须监听 touchstart,并兼容鼠标设备用 pointerdown 更稳妥。
立即学习“前端免费学习笔记(深入)”;
el.addEventListener('pointerdown', handler, { passive: false })
passive: false 是必须的,否则 iOS Safari 会忽略 preventDefault()(虽然这里不一定需要,但留着不碍事)click 和 touchstart —— 会导致双触发,用 pointerdown 一个事件足矣实际效果取决于三个地方:定位是否随滚动实时校准、缩放是否走 GPU 合成、事件是否绕过 click 延迟。漏掉任意一点,波纹就会“飘”“卡”或“延迟”。