SVG样式中的CSS类名是全局的吗?

3
如果在HTML body中有多个SVG元素,每个SVG元素引用一个CSS类名,并且这个类名在其中一个SVG元素中定义,那么所有的SVG元素都会受到这个样式的影响。我想知道这是否是设计上的问题,以及如何确保CSS类名仅对定义它的SVG元素有效。

<svg xmlns="http://www.w3.org/2000/svg" width=100 viewBox="0 0 15 10">
    <path class="iconMain" d="M7.5,9,1,4.78789l.46713-.91645L7.5,7.85543l6.03287-3.984L14,4.78789ZM14,1.91646,13.53287,1,7.5,4.98349,1.46713,1,1,1.91646l6.5,4.2121Z" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width=100 viewBox="0 0 15 10">
    <defs>
        <style>
            .iconMain {
                fill: #9cbacf;
            }
        </style>
    </defs>
    <path class="iconMain"
        d="M7.5,9,1,4.78789l.46713-.91645L7.5,7.85543l6.03287-3.984L14,4.78789ZM14,1.91646,13.53287,1,7.5,4.98349,1.46713,1,1,1.91646l6.5,4.2121Z" />
</svg>

https://codepen.io/napsta32/pen/ExOPGae


是的,这就是CSS的工作原理。类名是全局的。 - Robert Longson
是的,这就是CSS的工作方式。类名是全局的。 - Robert Longson
是的,这就是CSS的工作原理。类名是全局的。 - undefined
3个回答

1
你误解了defs的用法,它们用于定义图形元素,以便稍后与use标签一起使用。如果你放入的内容不是一个图形元素,它将直接进入文档中,比如样式或脚本。而且,即使defs是全局的,如果你在一个svg内定义了一个元素,你也可以在另一个svg中使用它。

<svg xmlns="http://www.w3.org/2000/svg" width=100 viewBox="0 0 15 10">
  <defs>
  <circle id="circle_defined_in_first_svg" cx="1" cy="2" r="6" />
 </defs>
  
    <path class="iconMain" d="M7.5,9,1,4.78789l.46713-.91645L7.5,7.85543l6.03287-3.984L14,4.78789ZM14,1.91646,13.53287,1,7.5,4.98349,1.46713,1,1,1.91646l6.5,4.2121Z" />
</svg>

<svg xmlns="http://www.w3.org/2000/svg" width=100 viewBox="0 0 15 10">
    <defs>
        <style>
            .iconMain {
                fill: #9cbacf;
                background-color:pink;
            }
        </style>       
      <script>
        var variableInsideDef = 7987;
      </script>      
    </defs>
    <path class="iconMain"
        d="M7.5,9,1,4.78789l.46713-.91645L7.5,7.85543l6.03287-3.984L14,4.78789ZM14,1.91646,13.53287,1,7.5,4.98349,1.46713,1,1,1.91646l6.5,4.2121Z" />
  
  <use x="5" y="5" href="#circle_defined_in_first_svg"/>
  
</svg>

<p class="iconMain"> P ELEMENT IN ROOT AFFECTED BY THE STYLE INSIDE DEF</p>

<script>
  alert("Variable declared inside def: " + variableInsideDef)
</script>

我能想到的唯一方法是为每个特定的SVG元素设置不同的类,这样你就可以对其应用特定的样式...

谢谢。我之前不了解defs的存在。但是,如果我去掉defs,只定义style而没有它,问题仍然存在。 - akonsu
你可以为每个svg使用不同的类吗,这样每个svg都能有自己的样式吗? - Paulo Fernando
是的,我可以。Webpack对此非常有用。如果我使用scss模块,它可以生成唯一的CSS类名。我只是试图理解正在发生的事情,以及是否有一种方法可以为SVG中的每个style创建一个“作用域”。 - akonsu
我明白了,是的,我不知道有什么办法... - Paulo Fernando
我明白了,是的,我不知道有什么办法... - Paulo Fernando
显示剩余5条评论

0
是的,SVG内容是全局内容。
  • id属性会重复,后续的SVG将使用具有相同id第一个元素

  • <style>变成了全局样式。

最简单、现代的解决方法是:

创建一个本地 JavaScript Web组件(JSWC)

shadowDOM中包装innerHTML,创建所需的“作用域”,
这样样式就不会泄漏进来(除了CSS属性,部分可继承样式
... 或者泄漏出去

语义化HTML:

    <svg-chevron></svg-chevron>
    <svg-chevron color="green"></svg-chevron>
    <svg-chevron color="blue"></svg-chevron>
    <svg-chevron color="gold"></svg-chevron>

然后创建:

<svg-chevron></svg-chevron>
<svg-chevron color="green"></svg-chevron>
<svg-chevron color="blue"></svg-chevron>
<svg-chevron color="gold"></svg-chevron>

<style>
 [color] { --iconhovercolor:beige }
 path { fill:red!important } /* never applied to shadowDOM */
</style>

<script>
  customElements.define('svg-chevron', class extends HTMLElement {
    connectedCallback(){
      Object.assign( this.style , {
        display : "inline-block",
        width   : "100px",
        cursor  : "pointer"
      });
      let color = this.getAttribute("color") || "black";
      let d = "m75 90-65-42 5-9 60 40 60-40 5 9zm65-71-5-9-60 40-60-40-5 9 65 42z";
      this.attachShadow({mode:"open"})
          .innerHTML = `<style>
                          path{fill:${color}}
                          svg:hover{background:var(--iconhovercolor,red)}
                        </style>
                        <svg viewBox="0 0 150 100">
                         <path d="${d}" stroke="${color}"/>
                        </svg>`;
      this.onclick = (evt) => {
           console.log("You clicked me!", color);
      }
    }
  });
</script>

重构 Web 组件为 <svg-icon>,你就拥有了自己的图标设计系统:

  <svg-icon is="chevron"></svg-icon>
  <svg-icon is="menu"></svg-icon>
  <svg-icon is="settings"></svg-icon>

fishice来自另一个StackOverflow问题的图标:

<style>
  svg-icon {  --iconhovercolor:beige;  width: 120px  }
</style>

<svg-icon></svg-icon>
<svg-icon is="fish" color="green"></svg-icon>
<svg-icon is="fish" color="blue"></svg-icon>
<svg-icon color="teal"></svg-icon>

<script>
  customElements.define('svg-icon', class extends HTMLElement {
        connectedCallback() {
          Object.assign(this.style, {
            display: "inline-block",
            cursor: "pointer"
          });
          let is = this.getAttribute("is") || "ice";
          let color = this.getAttribute("color") || "black";
          let d = {
            "fish": "m64 46s-.7 2.7-2.6 5.3c-1.9 2.5-4 3.4-4 3.4s11.53 0 21.23 2.2c9.7 2 17.5 10.12 17.5 10.12s-.8-1.2-1.8-3.02c-1-1.8.8-4.4.8-4.4s-2.7.5-5.8-.2c-3-.6-3.9-5.2-3.9-5.2s-2.8.5-6 .5-3.6-4.5-3.6-4.5-4.5 1.2-7.7-.2c-3.13-1.4-4.03-4-4.03-4zm-2.5 10.7c-24.1 0-39.4 22.62-39.4 22.62l9 3.1h-6.8s8.2 16.7 27.9 20c.7 1.4 1.8 3.5 3.4 4.8 2.6 2 7.6 3.7 7.6 3.7s-3.3-2.9-3.7-5c-.2-.9-.3-2-.3-2.9 1.6 0 3.3-.1 5.1-.3 28.33-2.7 32.43-17.7 41.13-17.7 8.8 0 21 10.6 21 10.6l-11-16.9 11-14.66c-1.6 1.66-8.1 8.76-19.1 8.76-12.5 0-21.9-15.76-45.98-15.76zm5.93 5c2.1.8 3.6 3.1 3.6 5.22 0 1.9-1.7 3.7-3.9 4.5 1.7-1.1 2.5-2.7 2.5-4.5 0-2.02-.6-4.12-2.2-5.22zm-18.03 1.3c5.2 2.62 7.6 10.12 7.6 16.82s-3 12.4-8.1 15.1c4-3.6 5.9-9 5.9-15.1 0-6.2-1.4-13.3-5.4-16.82zm-7.4 3.82c1.9 0 3.5 1.6 3.5 3.5s-1.6 3.5-3.5 3.5c-2 0-3.6-1.6-3.6-3.5s1.6-3.5 3.6-3.5zm34.03 1.2c2 .8 3.7 3.1 3.7 5.2 0 1.9-1.8 3.7-4 4.5 1.6-1.1 2.5-2.7 2.5-4.5 0-2-.5-4.1-2.2-5.2zm7.2 5.9c2.3.8 3.8 3.1 3.8 5.2 0 1.9-1.8 3.7-4 4.5 1.7-1.1 2.5-2.7 2.5-4.5 0-2-.5-4.1-2.3-5.2zm-16 1.1c2.1.8 3.6 3.1 3.6 5.2 0 1.9-1.7 3.7-3.9 4.5 1.7-1.1 2.5-2.7 2.5-4.5 0-2-.6-4.1-2.2-5.2zm7.9 6.2c2.1.8 3.7 3.1 3.7 5.2 0 1.9-1.8 3.7-3.9 4.5 1.6-1.1 2.4-2.7 2.4-4.5 0-2-.6-4.1-2.2-5.2zm-7.9 6.8c2.2.8 3.8 3.1 3.7 5.2.1 1.9-1.7 3.7-3.9 4.5 1.7-1.1 2.5-2.7 2.5-4.5 0-2-.6-4.1-2.3-5.2z",
            "ice": "m15.5 39h-1.6c6.9 6.64 6.6 11.74 10.1 19.64 2.9 6.4 5.8 11.6 10.5 15.1h-12.2c-1.5 0-2.9 1.3-2.9 2.9v.1c0 1.6 1.4 2.9 2.9 2.9h94.5c1.6 0 3-1.3 3-2.9v-.1c0-1.5-1.4-2.9-3-2.9h-26.4c.1-.7.2-1.4.2-2.1 0-8.9-7.4-16.1-16.5-16.1s-16.5 7.2-16.5 16.1c-1.6.7-3.3 1.3-5 1.5-4 .4-7.5-.9-10.5-2.8-5.4-3.3-9.1-8.6-11.5-14.2-1.6-3.8-3.8-7.3-6-10.8 1 1.1 2 2.3 2.9 3.5 2.8 3.2 4.6 7.1 6.8 10.7 2.1 3.7 5.2 6.8 8.9 9.1 3 1.8 6.8 2.2 10.2 2 1.1-.1 2.3 0 3.3-.4 2.2-3 .9-7.3-.4-10.1-.5-1.1-1-2.4-1.8-3.4-1.4.7-2.9 1.4-4.3 1.9 1-2.2 3.1-4.5 1.7-5.7-1.8-1.7-3.3-3.6-5.4-5-.9 1.5-1.7 3.1-2.7 4.4-.1-2.1-.1-4.3-.3-6.5-2.6-1.6-6.1-3.34-9.5-4.34-.6.2-.2 4.04-.5 5.74-.9-2.2-1.7-4.44-2.5-6.54-3.5-.80-11.1-1.7-15.5-1.7zm5.9 41.14c0 8.2 8.7 15.4 21.9 19.6h52.5c13.2-4.2 21.9-11.4 22-19.6h-96.4z"
          }[is];
          this.attachShadow({mode:"open"})
              .innerHTML = `<style>
                              path{fill:${color}}
                              svg{vertical-align:top}
                              svg:hover{background:var(--iconhovercolor,red)}
                            </style>
                            <svg viewBox="0 0 140 140"><path d="${d}" stroke="${color}"/></svg>`;
          this.onclick = (evt) => {
               console.log("You clicked me!", is, color);
          }
        }});
</script>


0
内联SVG包含<style>元素将像任何其他附加的样式表一样影响全局文档样式。
正如Paulo Fernando所指出的那样。
请参考这个例子,它也会影响HTML元素。

<svg xmlns="http://www.w3.org/2000/svg" width=100 viewBox="0 0 15 10">
    <path class="iconMain" d="M7.5 9l-6.5-4.2l0.5-0.9l6 4l6-4l0.5 0.9zm6.5-7.1l-0.5-0.9l-6 4l-6-4l-0.5 0.9l6.5 4.2z" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width=100 viewBox="0 0 15 10">
    <defs>
        <style>
            .iconMain {
                fill: #9cbacf;
            }
          p{
            color: red
          }
          body{
            background: #ccc
          }
          h1{
            color:green
          }
        </style>
    </defs>
    <path class="iconMain"
        d="M7.5 9l-6.5-4.2l0.5-0.9l6 4l6-4l0.5 0.9zm6.5-7.1l-0.5-0.9l-6 4l-6-4l-0.5 0.9l6.5 4.2z" />
</svg>

<h1>New Heading</h1>
<p>New paragraph</p>

使用案例1:图标

常见做法:尽量保持您的图标图形尽可能中立,以便为每个实例更改填充/描边颜色等样式。

您可以从流行的图标库(如fontAwesome、feather icons、Material Icons等)中获取灵感。

主要概念:将您的图标组织为<symbol>元素,并通过<use>元素创建实例。

svg{
  width:1em;
  border:1px solid #ccc;
}
<svg viewBox="0 0 15 10">
  <use href="#angle-double-down" fill="red"/>
</svg>

<svg viewBox="0 0 15 10">
  <use href="#angle-double-down" fill="green"/>
</svg>

<svg viewBox="0 0 15 10">
  <use href="#angle-double-down" fill="purple"/>
</svg>


<!-- hidden svg icon asset -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 10" style="position:absolute; height:0; width:0;">
  <symbol id="angle-double-down">
    <path d="M7.5 9l-6.5-4.2l0.5-0.9l6 4l6-4l0.5 0.9zm6.5-7.1l-0.5-0.9l-6 4l-6-4l-0.5 0.9l6.5 4.2z" />
  </symbol>
</svg>

在某种程度上,您还可以使用外部<use>引用,例如
<svg viewBox="0 0 15 10">
  <use href="icons.svg#angle-double-down" fill="green"/>
</svg>

然而,关于渐变、遮罩剪辑路径等方面存在一些限制或问题(相关链接:SVG忽略渐变样式)。
用例2:具有预定义颜色的复杂SVG图形
并不总是需要操作SVG样式,例如当您显示一个复杂的矢量插图时。
在这种情况下,只需使用引用SVG文件的<img>元素。
该文件也可以包含样式规则,但不会覆盖任何全局HTML元素样式。

<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' viewBox='0 0 15 10'%3E%3Cdefs%3E%3Cstyle%3E .iconMain %7B fill: %239cbacf; %7D body %7B background: red; %7D %3C/style%3E%3C/defs%3E%3Cpath class='iconMain' d='M7.5,9,1,4.78789l.46713-.91645L7.5,7.85543l6.03287-3.984L14,4.78789ZM14,1.91646,13.53287,1,7.5,4.98349,1.46713,1,1,1.91646l6.5,4.2121Z' /%3E%3C/svg%3E" />

否则,使用原生 Web 组件可能是一个很好的选择,如此处所述这里:"我如何改变 'svg' 元素的颜色?"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接