嵌入矩阵:谁能被 CSS 管到
同一颗心,用五种方式放进页面。然后按下面两个开关:一个让外部 CSS 把 fill 改为绿色,一个改宿主文字色(currentColor 的来源)。观察哪些跟随变化、哪些不受影响——这就是「图标系统为什么偏爱 inline / <use>」的根本原因。
| 把同一段 SVG 这样放进页面 | 外部 CSS 能改它内部? | JS / :hover? | currentColor 继承宿主? |
|---|---|---|---|
inline <svg> |
✅ 完全 | ✅ | ✅ |
<use href="#id"> (同文档) |
✅ 可穿透 | ✅ | ✅ |
<img src=".svg"> |
❌ 隔离 | ❌ | ❌ |
background-image: url() |
❌ | ❌ | ❌ |
<object> / <iframe> |
❌ 跨文档 | ⚠️ 独立文档 | ❌ |
图标系统为什么偏爱 inline / <use> 而非 <img>,根源就在这张表——本页逐格实测每一项;那几个 ❌ 隔离格,param() 提案想给它们开一扇传参口。
1 · 五种写法
只有 inline 和同文档 <use> 把图形真正接入了当前文档的 DOM 树,所以外部 CSS 选择器能选中、currentColor 能继承宿主的 color、:hover 也能命中。<img> 与 background-image 把
SVG 当作一张沙箱位图——内部 DOM 对外不可见;<object> / <iframe> 是另一个独立文档,外部 CSS 同样无法进入(但它内部的 <style> 有效)。
2 · 复用三件套:<defs> / <use> / <symbol>
上面那个能被 CSS 改色的 <use>,正是图标 sprite 系统的地基:把图形定义一次放进 <defs> 或 <symbol>(不渲染、待引用),页面各处用 <use href="#id"> 克隆。<symbol> 比 <g> 多一个自带 viewBox,所以每次 <use> 都能缩放贴合。
<use> 克隆出的内容在一棵 shadow tree 里,外部 CSS 选不中它的内部元素(写 use circle {…} 没用)。但继承类属性 (fill / color / --var) 能从
<use> 元素本身穿透下去——所以改色靠的是「在 use 上设 fill,让内部继承」,而不是直接选中内部。主题化图标的细节见 presentation attribute 一页。
3 · 两个 SVG 的反直觉特性
其一:SVG 没有 z-index。 元素的层叠顺序完全等于文档顺序——写在后面的覆盖前面的,要调整层级只能改变 DOM 位置(或用 <use> 重新引用)。给 SVG 子元素写 z-index 无效。
其二:pointer-events 在 SVG 里取值更多。 除了 auto/none,还有 visiblePainted(默认:只有被填充 /
描边的可见部分响应点击)、fill(透明填充区也响应)、stroke、all。因此一个只描边的圆环,默认点击中间空心处不会触发——除非设 pointer-events: fill。