
Fabric.js 默认无法为透明对象单独设置不透明的模糊阴影,但可通过 Canvas 2D API 的 filter 属性在渲染后阶段手动绘制高斯模糊区域,绕过对象自身 opacity 对 shadow 的影响。
fabric.js 默认无法为透明图形单独设置不透明的模糊阴影,但可通过 canvas 2d api 的 `filter` 属性在渲染后阶段手动绘制高斯模糊区域,绕过对象自身 opacity 对 shadow 的影响。
在 Fabric.js 中,shadow 属性受对象整体不透明度(opacity)和填充透明度(如 fill: 'rgba(0,0,0,0)')双重影响——即使对象完全透明,其阴影也会被“继承”为不可见或极淡,导致模糊阴影失效。官方 fabric.Shadow 不支持独立控制阴影不透明度,因此直接配置无法达成目标。
推荐解决方案:利用 after:render 钩子 + 原生 Canvas 2D filter 绘制独立模糊区域
该方法将模糊效果从 Fabric 对象逻辑中解耦,直接操作底层渲染上下文,确保模糊仅作用于指定几何区域,且不受对象 fill/opacity 干扰:
const canvas = new fabric.Canvas('cnv');
// 创建一个完全透明的占位图形(不参与视觉渲染,仅作定位参考)
const poly = new fabric.Polygon([
{ x: 100, y: 100 },
{ x: 180, y: 80 },
{ x: 160, y: 160 }
], {
left: 0,
top: 0,
fill: 'transparent', // 关键:保持透明,不干扰视觉
stroke: 'none',
selectable: false,
evented: false // 禁用交互,避免干扰
});
// 自定义模糊绘制函数
const drawBlurPolygon = () => {
const ctx = canvas.getContext();
ctx.save();
// 应用 CSS Filter 风格的高斯模糊(单位:px)
ctx.filter = 'blur(15px)';
// 重置变换矩阵,确保坐标系与 Fabric 一致(需考虑 canvas.viewportTransform)
const vpt = canvas.viewportTransform;
ctx.setTransform(vpt[0], vpt[1], vpt[2], vpt[3], vpt[4], vpt[5]);
// 绘制多边形路径并填充(颜色即为模糊后的“阴影”色)
ctx.beginPath();
poly.points.forEach((p, i) => {
const transformed = fabric.util.transformPoint({ x: p.x, y: p.y }, vpt);
if (i === 0) ctx.moveTo(transformed.x, transformed.y);
else ctx.lineTo(transformed.x, transformed.y);
});
ctx.closePath();
ctx.fillStyle = 'rgba(255, 100, 100, 0.7)'; // 模糊区域颜色与不透明度
ctx.fill();
ctx.restore();
};
// 注册到 after:render 生命周期,在 Fabric 渲染完成后叠加模糊层
canvas.on('after:render', drawBlurPolygon);
canvas.add(poly);
canvas.renderAll();
✅ 关键要点说明:
- 使用
fill: 'transparent'替代rgba(0,0,0,0),语义更清晰且兼容性更稳; -
evented: false和selectable: false可防止透明图形意外拦截鼠标事件; -
ctx.setTransform(...)同步 Fabric 视口变换(缩放、平移、旋转),确保模糊区域精准贴合图形位置; -
ctx.filter = 'blur(Npx)'是原生高性能模糊,效果远优于多重 shadow 叠加; - 模糊颜色(如
rgba(255,100,100,0.7))可自由定制,其 alpha 值独立于图形 opacity。
⚠️ 注意事项:
- 此方案依赖浏览器对
ctx.filter的支持(Chrome 54+、Firefox 49+、Safari 15.4+),旧版 Safari 需降级为shadowBlur+ 多层绘制; - 若画布启用了
enableRetinaScaling,需在drawBlurPolygon中手动处理像素比(canvas.getZoom() * window.devicePixelRatio); - 高频
after:render调用可能影响性能,建议对静态图形使用canvas.renderAll()后移除监听,或结合canvas.requestRenderAll()按需触发。
通过此方法,你不仅能实现任意形状(矩形、圆形、多边形)的独立模糊“伪阴影”,还可进一步扩展为发光、毛玻璃等高级视觉效果——真正释放 Canvas 2D 与 Fabric.js 协同的潜力。











