Canvas无法直接实现径向模糊,需用多层渐变透明同心圆模拟光圈效果:从中心向外扩展、半径增大、透明度衰减,并严格适配DPR与禁用插值以保边缘锐利。

Canvas本身不支持直接的“径向模糊”滤镜,但可以通过逐帧绘制多层缩放/渐变透明的同心圆来模拟相机光圈开合时的视觉扩散效果——这本质上是用大量带透明度的圆形叠加,营造出由中心向外辐射、逐渐虚化的感觉。
这种实现方式不是GPU加速的真模糊,而是视觉欺骗式光圈动画,轻量、可控、兼容性好,适合加载页、转场或UI反馈场景。
核心思路:用同心圆堆叠代替径向模糊
浏览器没有 ctx.radialBlur() 这样的 API。所谓“光圈效果”,关键在于两点:
- 所有图形从同一中心点(如画布中心)向外扩展
- 越靠外的环越透明、越大、颜色略淡,形成“发散+衰减”感
因此,不需要高斯模糊算法,只需在每帧中:
- 生成若干个新圆(位置固定,半径小,不透明)
- 让已有圆持续增大半径 + 降低透明度
- 透明度归零时移除该圆
避免模糊的关键:适配设备像素比(DPR)
如果光圈边缘看起来毛糙、发虚,大概率不是算法问题,而是 Canvas 在高清屏上被错误缩放。必须做 DPR 适配:
- 获取
window.devicePixelRatio - 将 canvas 元素的
width/height设为css尺寸 × dpr - 用
ctx.scale(dpr, dpr)统一坐标系,确保 1px 线条对应 1 物理像素 - 禁用插值缩放:
canvas.style.imageRendering = 'crisp-edges'
否则,哪怕只是画一个圆,高 DPI 屏上也会因浏览器双线性插值而边缘糊掉。
提升真实感的三个细节技巧
纯随机圆容易显得杂乱。加一点控制,更像专业镜头光圈:
-
起始半径微调:不要都从 r=1 开始,可设为
r = 3 + Math.random() * 2,避免所有圆同步“炸开” -
透明度衰减非线性:用
c4 *= 0.985而非减固定值,让淡出更自然 -
色彩倾向控制:光圈常带暖调,可让
c1(红)初始值偏高,c2(绿)略低,c3(蓝)最低,模拟镀膜反光
简化版可运行代码结构(含 DPR 修复)
以下精简逻辑,去掉了原始示例中易引发内存泄漏的 splice 遍历删除,改用 filter:
rgba(${c.c1},${c.c2},${c.c3},${c.c4})不复杂但容易忽略。











