canvas是绘制图片倒影最可靠方案:先加载图片,用ctx.scale(1,-1)翻转坐标系并调整y偏移绘制倒影,再叠加createLinearGradient渐变遮罩,同时缓存canvas实例提升性能。

用 canvas 绘制图片倒影最可靠
HTML5 本身没有原生「倒影」CSS 属性,box-reflect 是 WebKit 旧私有属性,现代浏览器基本不支持(Chrome/Firefox/Edge 均已废弃)。真正跨浏览器、可控性强的做法是用 canvas 手动翻转并绘制:先加载图片,再以 y 轴为对称线,在 canvas 下方画一个垂直翻转的副本,并叠加半透明遮罩。
关键点:
-
canvas需足够高,容纳原图 + 倒影(建议高度 = 原图高 × 2.2,留出间距和渐变余量) - 倒影绘制必须用
ctx.scale(1, -1)翻转坐标系,再调整y偏移,否则图像会镜像错位 - 渐变遮罩要用
ctx.createLinearGradient()从倒影顶部向下设透明度变化,不能靠 CSSopacity整体压暗
drawImage 翻转时 y 坐标容易算错
直接调 drawImage(img, dx, dy, dw, dh) 画倒影不行——它不支持翻转。必须配合 ctx.save() / ctx.restore() 和坐标变换。常见错误是把翻转后的 y 设成 img.height * 2,结果倒影被画到画布外。
正确做法:
立即学习“前端免费学习笔记(深入)”;
- 先
ctx.translate(0, img.height * 1.1)把原点移到倒影起始位置 - 再
ctx.scale(1, -1)垂直翻转 - 最后
drawImage(img, 0, 0)—— 此时图像自然向上“长”出倒影区域 - 记得在翻转前
ctx.globalAlpha = 0.6控制不透明度
CSS -webkit-box-reflect 已不可靠,别依赖
虽然部分老教程还写 style="-webkit-box-reflect: below 0px linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,0.3));",但实测在 Chrome 90+、Firefox 100+、Edge 110+ 中完全无效,且无降级提示。Safari 15.4 之后也已移除支持。用它上线等于放弃倒影功能。
如果你只是想快速预览,可用临时方案:
- 仅 Safari 14–15.3 测试环境可试
-webkit-box-reflect - 其他场景一律走
canvas,或服务端生成带倒影的静态图 - 切勿用
transform: scaleY(-1)对img元素做伪倒影——无法叠加渐变,且会触发 layout 重排
性能注意:避免每帧重绘,倒影图可缓存
如果页面有多个相同图片需倒影(比如商品列表),每次 onload 都新建 canvas 并重绘浪费资源。应该按图片 src 做 key 缓存 HTMLCanvasElement 实例。
简单缓存逻辑:
- 用
Map存src → canvas映射 - 首次加载时生成带倒影的 canvas,后续直接复用
- 监听
img.naturalWidth === 0防止未加载完就读尺寸 - 移动端尤其要注意:canvas 宽高超过屏幕宽度 2 倍可能触发渲染降级
倒影看似简单,但跨浏览器一致性和性能边界很窄——canvas 是目前唯一能同时控制翻转精度、渐变停靠点、透明通道的方案。别省那几行代码去碰私有属性,真要兼容就老老实实 draw。










