动态水波倒影本质是四层叠加,核心为canvas像素级uv偏移:先翻转绘制半透明倒影,再通过双线性插值逐帧偏移采样,叠加多频扰动与渐变遮罩实现自然效果。

网页版动态水波倒影,本质是「原图 + 倒影区域 + 水面扰动 + 渐变遮罩」四层叠加,核心不在滤镜,而在 Canvas 像素级 UV 偏移。它不依赖 WebGL 或第三方库,纯 HTML5 + JavaScript 即可实现,关键在于控制好扰动逻辑与绘制节奏。
倒影区域必须手动构建
浏览器已废弃 -webkit-box-reflect,CSS 无法生成可控倒影。正确做法是:
- 将 canvas 高度设为原图高 × 2.2(预留间距和渐变空间)
- 用
ctx.save()→ctx.translate(0, imgHeight * 1.1)→ctx.scale(1, -1)→drawImage(img, 0, 0)翻转绘制倒影 - 倒影绘制前设
ctx.globalAlpha = 0.55控制基础透明度,避免死黑
水面扰动靠像素坐标偏移
水波倒影的“动”来自对倒影图像的逐帧位移映射,不是简单加动画或滤镜:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 先用
ctx.getImageData()读取倒影区域原始像素(注意:需同源或设置crossOrigin="anonymous") - 对每个像素
(x, y)计算偏移量:dx = Math.sin(y * 0.015 + time) * 4dy = Math.cos(x * 0.02 + time * 0.6) * 2 - 用双线性插值从原倒影图像采样偏移后坐标,避免锯齿;直接
putImageData()会丢失平滑度 - 幅度建议 2–6px,过大图像撕裂,过小无感
时间驱动与性能优化要点
流畅动画取决于帧节奏与内存复用:
- 必须用
requestAnimationFrame驱动,time += 0.03统一推进相位,禁用setInterval - 预分配
ImageData对象(如const buffer = ctx.createImageData(w, h)),每帧复用,避免频繁 GC - 限制画布尺寸(推荐 ≤ 800×600),大图先缩放再处理;移动端可降采样至 devicePixelRatio=1
- 倒影区域只对下半部分扰动(y > 原图底部位置),上半部保持静止更符合视觉习惯
自然感靠多层扰动+渐变遮罩
单频正弦波太机械,真实水波需叠加与衰减:
- 叠加两组频率:主波(低频大振幅)+ 次波(高频小振幅),例如
yOffset = sin(y*0.01 + t)*5 + sin(y*0.07 + t*1.3)*1.5 - 在倒影顶部添加
createLinearGradient(0, 0, 0, imgHeight*0.4),从透明到底部 40% 不透明,模拟水面反光衰减 - 可选:在扰动后叠加轻微高斯模糊(用两次
drawImage缩放模拟),增强液体质感
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










