20:内联 SVG 的样式 – 能力与局限性

内联 SVG 可以被“样式化”,因为一旦你将它放在页面上,它就自带填充、描边等等。这很棒,也是使用内联 SVG 的一种完全可行的方式。但你也可以通过 CSS 来为内联 SVG 设置样式,这也很棒,因为我想对我们很多人来说,CSS 是我们感到强大和舒适的地方。

它的工作方式与你预期的几乎一样。这是一个简单的示例

<svg>
  <rect class="my-rect" ... />
</svg>
.my-rect {
  fill: blue; /* remember it's fill not background, teamsters */
}

可以说,CSS 比 SVG 元素本身的样式属性拥有“更多权力”。如果该<rect>上带有fill="red",那么 CSS 仍然会“胜出”。你可能会认为情况相反,因为样式属性看起来像内联样式一样强大,但事实并非如此。不过,内联样式确实很强大。

同样,如果发生任何更具体的事件,CSS 规则就不会级联。例如

<g class="parent">
  <rect fill="blue" />
</g>
.parent {
  fill: red;
}

在这种情况下,CSS 输了,因为蓝色更具体地应用于矩形。

如果我计划通过 CSS 为 SVG 设置样式,我通常发现最简单的方法是完全不使用 SVG 元素的样式属性。

重要提示!

我们已经花时间讨论了<use>。假设情况如下

<svg>
  <symbol viewport="0 0 100 100" id="thing">
    <rect class="child" ... />
  <symbol>
</svg>

<svg class="parent">
  <use xlink:href="#thing" />
</svg>

最终“子元素”会被放到“父元素”中,对吧?没错。所以这应该可以工作?

.parent .child {
  fill: red;
}

但它不行。

<use>的工作方式是克隆该<symbol>并将它放入第二个 SVG 中的“Shadow DOM”。你无法使用这样的选择器穿透 Shadow DOM。就是不行。也许将来会有解决方案,但现在还没有。

你可以这样做

.parent {
  fill: red;
}

如果中间没有更具体的内容,则该填充将级联并影响子元素。或者

.child {
  fill: red;
}

并影响该子元素的所有实例。但两者不能兼得。

如果你确实需要不同样式的相同内容…

只需复制<symbol>或你需要的内容即可。绝大多数信息都将相同,GZip 会将相同文本当做早餐吃掉。