水滴扩散效果必须用Canvas 2D实现,因CSS仅支持transform缩放+opacity淡出,无法模拟波纹传播的物理感;真实效果需逐帧控制半径线性增长、alpha独立衰减、多层透叠隔离及超出剔除,且坐标校准、clearRect清屏、requestAnimationFrame驱动与数量限制均为必要约束。

水滴扩散过渡效果必须用 Canvas 2D 实现,CSS 无法模拟波纹传播的物理感——它只能做缩放+淡出,而真实水滴有中心凹陷、边缘扰动、透明度非线性衰减,这些都得靠逐帧像素控制。
为什么不能用 CSS transition 或 animation 做水滴扩散
CSS 的 transform: scale() + opacity 只能触发单次匀速变化,无法做到:
- 半径按固定增量(如 += 3)线性扩张,而非乘法加速
- 每个波纹独立控制 alpha 衰减速率(比如 0.05)
- 多层波纹叠加时,ctx.globalAlpha 需在每次 arc() 前重设,否则透叠污染后续绘制
- 扩散终点不是“消失”,而是半径超出画布后主动剔除对象,避免 ripples 数组无限膨胀
Canvas 中点击生成水滴的核心校准步骤
漏掉坐标校准,水滴永远出现在左上角:
- 必须用 canvas.getBoundingClientRect() 获取画布视口位置
- 点击坐标要减去 rect.left 和 rect.top
- 如果 canvas 设了 width/height 属性(非 CSS 缩放),还要除以 rect.width / canvas.width 补 DPI 缩放
- 移动端得监听 touchstart 并取 touches[0],不能只绑 click
requestAnimationFrame 驱动动画的三个硬约束
用 setInterval 会卡顿或跳帧,必须满足:
- 每帧开头调用 ctx.clearRect(0, 0, canvas.width, canvas.height),不清就糊成一团
- 每个水滴对象含独立状态:x、y、radius、alpha、decay
- radius 增长用加法(r.radius += 3),不是乘法(*= 1.1),否则越扩越快失真
- 同时存在的水滴数建议上限设为 30,高频点击时用 ripples.length > 30 && ripples.shift() 保性能
最容易被忽略的是:多个水滴共用一个 draw() 循环,但每个 arc() 前必须单独设 ctx.globalAlpha;设一次就全局生效,会导致后画的波纹把前面的“盖”成全透明。



















