如何仅将CSS样式应用于特定SVG?
你遇到的这个问题确实很常见——SVG内部定义的<style>默认是全局作用域的,所以后面SVG里的样式规则会覆盖前面的,导致所有SVG的元素都应用最后生效的样式。好在我们有几个靠谱的办法解决这个问题,而且不用给SVG加类、不用iframe,还能让用户用统一的类名。
最优方案:使用:scope伪类
:scope伪类专门用来指代包含当前样式表的元素(这里就是当前的<svg>标签),用它来限定样式的作用域,就能让样式只作用于当前SVG内部的元素。
修改你的示例代码如下:
<svg> <style> :scope .colored { stroke: red; } </style> <line class="colored" x1="0" y1="0" x2="100" y2="100"></line> </svg> <svg> <style> :scope .colored { stroke: blue; } </style> <line class="colored" x1="0" y1="0" x2="100" y2="100"></line> </svg>
这样修改后,第一个SVG里的.colored只会变成红色,第二个的只会变成蓝色,完全不会互相干扰。而且用户依然只需要记住colored这个统一类名,不需要区分不同的类标识。
兼容性说明
目前主流浏览器(Chrome、Firefox、Safari 15.4+、Edge)都支持SVG中的:scope伪类,对于绝大多数场景来说足够用了。
替代方案:给SVG添加唯一ID(如果允许的话)
如果你的场景需要兼容更老的浏览器,而你又能给SVG标签添加id(你提到不能给SVG元素加类,但没说不能加id),可以用ID来限定作用域:
<svg id="svg-1"> <style> #svg-1 .colored { stroke: red; } </style> <line class="colored" x1="0" y1="0" x2="100" y2="100"></line> </svg> <svg id="svg-2"> <style> #svg-2 .colored { stroke: blue; } </style> <line class="colored" x1="0" y1="0" x2="100" y2="100"></line> </svg>
这个方案兼容性更好,唯一的小缺点是需要给每个SVG分配唯一ID,但用户依然不用关心类名的变化,还是用统一的colored类。
为什么原来的代码会失效?
因为SVG的<style>元素默认是挂载到全局文档的样式表中的,不管它在哪个SVG内部,样式规则都是全局生效的。后面的.colored { stroke: blue; }会覆盖前面的.colored { stroke: red; },所以所有带colored类的元素都会变成蓝色。而:scope或者ID选择器则把样式规则的作用域限制在了当前SVG内部,避免了全局覆盖。
内容的提问来源于stack exchange,提问作者Daniel

