HTML5 Canvas动态波浪纹需用3–4段三次贝塞尔曲线分段拟合正弦波,通过相位偏移实现流动感,确保C¹连续、波峰波谷水平切线约束,并叠加双层波形与渐变填充增强真实感。

要在 HTML5 Canvas 中实现拟合度极高的动态波浪纹效果,核心不是“画一条曲线”,而是用多段连续、参数可控的三次贝塞尔曲线拼接成平滑周期性波形,并随时间偏移形成流动感。关键在于控制点的数学生成逻辑,而非手动调参。
用分段贝塞尔拟合正弦波形态
单条 bezierCurveTo() 无法表达完整波浪,需将一个波长(如 120px 宽)划分为 3–4 段三次贝塞尔曲线,每段覆盖约 1/4 或 1/3 波形。例如:从波谷→上升拐点→波峰→下降拐点→波谷,每两个关键点之间用一段贝塞尔拟合。
推荐参数策略:
- 设波长为 L,振幅为 A,当前相位偏移为 offset
- 对第 i 段(i = 0,1,2,3),计算其起点 P₀、终点 P₃ 的 y 值(基于正弦插值),再按切线方向设置控制点:
— 第一个控制点 P₁ 在 P₀ 右上方,x 偏移 ≈ L/6,y 偏移 ≈ 0.6A × cos(θ)
— 第二个控制点 P₂ 在 P₃ 左上方,x 偏移 ≈ −L/6,y 偏移 ≈ 0.6A × cos(θ+π/2) - 这样能保证段间一阶导数连续(C¹ 连续),视觉上无折角
动态偏移与循环更新机制
波浪“动”起来的本质是水平相位随时间匀速推进。不要重绘整条路径,而应:
立即学习“前端免费学习笔记(深入)”;
- 在动画帧中仅更新每段的 offset(如
offset = Date.now() * 0.002 % L) - 复用同一组相对控制点模板,仅对 x 坐标整体加 offset 并取模,避免跳变
- 使用
requestAnimationFrame驱动,配合clearRect()清除旧帧,再重绘新波形 - 若需双层波(快慢叠加),用两套不同周期、振幅、相速的 offset 分别计算
提升拟合精度的实用技巧
人眼对波峰/波谷处的平滑度最敏感,此处误差易被察觉:
- 在波峰和波谷位置强制插入“水平切线”约束:令该点两侧控制点 y 坐标严格相等,x 对称分布
- 避免使用过大的控制点距离——当
cp1y与cp2y相差超过 1.5×振幅时,曲线易出现多余拱起或凹陷 - 可先用 SVG 的
<path d="M... C...">在编辑器中调试理想控制点,再提取坐标迁入 Canvas - 添加轻微随机扰动(±2px)到控制点 y 值,可破除机械感,更接近真实水纹
闭合水面与色彩渐变增强真实感
单纯线条波浪缺乏体积感。建议:
- 绘制两条错开相位的波形路径:上层为波峰轮廓(细白线),下层为水面填充区域(带透明度的蓝-青渐变)
- 填充路径需闭合:从左端波底 → 沿上层波形 → 右端波底 → 直线回左端,再
fill() - 利用
createLinearGradient()设置垂直渐变,模拟光线折射变化 - 叠加半透明白色噪点图层(canvas 绘制小圆点阵),可强化表面张力细节



















