你以为 SVG 只能靠复制文件才能换颜色?今天一个 CSS 规范把它彻底原生化了
配了三年设计系统,今天才发现同一个 SVG 文件要在三个地方显示三种颜色这件事,从来没有标准解——inline 样式最多,外链文件永远是黑的。
以前你只有三条路:把 SVG 直接写在 HTML 里(每次换主题要改源码)、维护三份颜色不同的 SVG 文件(一个图标三份副本)、或者用 JavaScript 动态注入样式(性能开销另算)。无论哪条,SVG 的可缓存性和样式隔离都打了个对折。
W3C 在今年 7 月 14 日发布了 CSS Linked Parameters Module Level 1 的首个公开工作草案,第一次在 CSS 层给外链资源开了一个传变量的口子。Chrome 的支持提案也在推进中(issues.chromium.org/issues/41482962)。
param() 的三种传参方式
外链 SVG 内部用 env() 接收变量,然后在 HTML 或 CSS 这一侧用三种方式之一把值”穿墙”传进去:
第一种,通过 link-parameters CSS 属性:
img.primary-icon {
link-parameters: param(--theme-color, #6366f1);
}
img.danger-icon {
link-parameters: param(--theme-color, #ef4444);
}
同一个 square.svg,两行 CSS,各自拿到不同的主题色。
第二种,直接拼在 URL 碎片里:
<img src="icon.svg#param(--theme-color, green)" alt="..." />
适合不想动 CSS、只想在 HTML 层面控制的场景。
第三种,塞进 url() 的参数里:
.btn-icon {
background-image: url("icon.svg", param(--theme-color, currentColor));
}
hover 时直接改 link-parameters 的值就能切色,不需要换图片地址,也不需要 JavaScript。
外链 SVG 内部怎么接
SVG 这一侧不用改任何逻辑,只需要在属性值里写 env() 代替硬编码:
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="env(--theme-color, #000)"
d="M12 2L2 7l10 5 10-5-10-5z"/>
</svg>
env() 的第二个参数是兜底值,浏览器不认识 link-parameters 时会 fallback 到这个颜色,不至于白屏。整个 SVG 文件可以存一份,用在任何颜色主题下。
这件事为什么以前做不到
外链资源(img 的 src、background-image 的 url())和当前页面是分离的上下文,CSS 变量不跨域传递,这是浏览器安全模型的一部分。以前的解法都是在绕这个限制:内联 SVG 牺牲缓存、复制文件浪费磁盘、JS 注入徒增运行时开销。
link-parameters 本质上是在 URL 和 CSS 两条通道之外,给外链资源开了一条受控的样式注入路径。参数以 key-value 形式传递,SVG 内部用 env() 读取,浏览器的隐私边界没有打破,但前端工程化的一个十年痛点被解了。
现在能怎么用
这是一个还在草案阶段的功能,具体时间表取决于浏览器实现进度。但写到这里值得交代一下现状,免得你看完立刻去写生产代码然后骂我——Chrome 的 issue 已经开出去了,团队正在评估,这是好事。
现在的实际策略:
- 存量 SVG 不用动——给新引入的系统级图标加上 env() 接收参数就够了,渐进增强
- 设计系统里的高频图标优先改造——一个图标在不同按钮颜色下显示不同色的场景,现在靠复制文件解决,以后一份 + link-parameters 就够了
- 别为了用它而用它——如果你的 SVG 只有一种颜色,加这套机制是负优化
同一张图纸,同一个文件地址,页面里想让它是什么颜色,它就是什么颜色——这件事 CSS 终于开始认真对待了。
评论区
登录后可评论。