svg滤镜必须通过filter: url(#id)调用,且id须严格匹配中的值;滤镜需嵌在内,in与result需严格对应形成流水线,否则静默失效。

filter: url(#id) 是唯一能生效的调用方式
直接写 filter: blur(3px) 或 filter: drop-shadow(2px 2px 4px #000) 看似简单,但它们属于 CSS 原生滤镜,和 SVG 滤镜无关。SVG 滤镜必须通过 url(#id) 引用,且这个 id 必须严格匹配 <filter id="xxx"></filter> 中的值——大小写、空格、引号一个都不能错。
常见失效点:
-
filter: url(#blur)写成filter: url(#Blur)→ 静默失败(ID 大小写不一致) -
filter: url(#blur)漏了引号或括号 → 部分浏览器直接忽略 - 目标元素是
<img>或<div> 但没设 <code>display: block或尺寸 → 滤镜不触发(需有“绘画上下文”)滤镜定义必须嵌在
<filter></filter>不是独立可用标签,它必须包裹在<svg></svg>的<defs></defs>内。哪怕你只给普通 HTML 元素用,也得有一个<svg></svg>容器——可以隐藏:<svg width="0" height="0" style="position: absolute; left: -9999px;"><defs><filter id="myFilter">...</filter></defs></svg>。这些写法都会失效:
- 把
<filter></filter>直接丢在里(没包<svg><defs></defs></svg>) - 用外链 SVG:
url(https://cdn.com/filters.svg#myFilter)→ 跨域 + 安全策略双重拦截,现代浏览器基本拒绝 - 滤镜区域裁剪太紧:
<filter id="blur" x="0" y="0" width="100%" height="100%"></filter>→ 模糊边缘被切掉,建议至少设为x="-20%" y="-20%" width="140%" height="140%"
动态图像处理的关键:输入源(in)与输出命名(result)要对得上
SVG 滤镜是线性流水线,每一步的
in必须指向上一步的result,否则效果断链。比如想“先模糊再提亮”,顺序和命名必须严格对应:<fegaussianblur in="SourceGraphic" stddeviation="3" result="blurred"></fegaussianblur><fecomponenttransfer in="blurred"><fefuncr type="linear" slope="1.3"></fefuncr></fecomponenttransfer>
容易踩的坑:
- 漏写
result→ 下一步默认回退到SourceGraphic,前一步白做 -
in="myInput"但没 anywhere 定义过myInput→ 整个滤镜静默失败,浏览器不报错 - 用
<fecolormatrix></fecolormatrix>却漏写type属性 → 浏览器按matrix解析,只读前 20 个值,后面全丢弃
视频/Canvas 动态画面慎用复杂 SVG 滤镜
HTML5
<video></video>或<canvas></canvas>上叠加 SVG 滤镜虽可行,但性能敏感度远高于静态图片。尤其当滤镜含多层<fegaussianblur></fegaussianblur>、<feturbulence></feturbulence>或大范围width/height时,移动端易卡顿。实操建议:
- 优先用 CSS 原生滤镜处理视频基础调节(如
brightness(),contrast(),blur(1px)),它们硬件加速更成熟 - 若必须用 SVG 滤镜(例如需要多层阴影或自定义颜色矩阵),把
stdDeviation控制在 ≤3,width/height不超 130% - 避免在
requestAnimationFrame中频繁修改<fegaussianblur stddeviation></fegaussianblur>—— DOM 重绘开销大,改用 CSS 变量 +filter: url()组合更稳
真正难的不是写对语法,而是让每一步的
in和result在脑子里连成一条线;漏一个命名,整条流水线就断了,还查不出错在哪里。 - 把











