最优解是javascript定位+css自定义属性驱动动画:js仅计算并设置--x/--y坐标,css完成动画,兼顾性能与真实感;纯css方案限简单场景,canvas仅用于高保真水波。

移动端 H5 实现轻量又逼真的水面波纹点击扩散动效,关键不在“堆效果”,而在**精准模拟物理节奏 + 最小化渲染开销**。纯 CSS 无法做到真实定位与衰减扩散,Canvas 又容易过重;最优解是:用 JavaScript 定位 + CSS 自定义属性驱动动画,兼顾性能与观感。
用 CSS 自定义属性 + :hover/:active 做基础层(仅限简单场景)
如果目标是按钮、卡片等固定尺寸元素,且接受“近似居中”涟漪(不严格跟随手指落点),可先用纯 CSS 快速实现:
- 给容器设 position: relative; overflow: hidden;
- 用 ::after 伪元素做涟漪,初始 scale(0) + opacity(0)
- 动画用 ease-out,时长控制在 400–600ms,避免 linear 显机械
- 加 pointer-events: none 防止遮挡后续操作
缺点:涟漪中心始终是元素中心,不是点击点;iOS 上 :active 响应延迟明显,不适合追求精准交互的场景。
用 JS 动态注入坐标 + CSS 动画(推荐方案)
这是平衡轻量与真实的主流做法:JS 只负责计算和设置两个变量,动画完全由 CSS 承担,不操作 DOM、不 requestAnimationFrame,流畅不掉帧。
- 监听 touchstart(移动端必须,click 在 iOS 有 300ms 延迟)
- 用 getBoundingClientRect() 获取目标元素位置,再算出相对于左上角的 x/y
- 通过 element.style.setProperty('--x', x + 'px') 注入坐标到 CSS
- CSS 中写:left: var(--x); top: var(--y); transform: translate(-50%, -50) scale(0);
- 动画结束用 animationend 清除伪元素或重置变量,避免残留
注意:若元素有 border 或 transform,需从 clientX/Y 中减去对应偏移,否则涟漪会偏移——这是最常出错的地方。
用 Canvas 实现高保真水波(仅当必要时启用)
只有当需要真实物理感(如中心凹陷、边缘扰动、多波叠加、衰减正弦波)才上 Canvas。它更重,但不可替代:
- 监听 touchstart,取 touches[0] 坐标,用 getBoundingClientRect() 校准到 canvas 像素坐标
- 每个水波存为一个对象:{ x, y, radius, alpha, speed },生命周期独立管理
- 用 requestAnimationFrame 驱动,每帧更新半径与透明度,clearRect 后重绘所有活跃波纹
- 限制最大并发波纹数(如 ≤8 个),超出则丢弃最早的一个,防卡顿
适合产品首页主视觉、互动营销页等对质感要求高的场景;普通按钮、列表项完全没必要。
移动端适配细节不能漏
手指点击面积远大于鼠标光标,粗放处理会导致体验打折:
- 禁用 touch-highlight:加 -webkit-tap-highlight-color: transparent;
- 防误触:点击后加 100ms setTimeout 锁定,期间忽略新触发
- 圆角容器务必设 overflow: hidden,否则涟漪会溢出边界
- 避免在 scroll 中频繁触发,可加 passive: true 优化 touch 事件监听
不复杂但容易忽略。











