使用CSS操作外部SVG文件的样式属性

32

我正在尝试通过CSS操作外部的.svg文件。

HTML

<body>
    <div class="mysvg">
    <img src="decho.svg" alt="decho" width="200px"></img>
    </div>
</body>

CSS

->

CSS

div.mysvg img {
    opacity: .3;
    transition: opacity 1s linear 0s;
}
    div.mysvg img:hover {
    opacity: 1;
}
这段代码适用于不透明度,但不适用于fill或其他类似于stroke的SVG特定属性。我知道我不能在标签中这样做,但我已经找了几个小时,也没有找到使用svgobject正确的方法。

基本上,我的问题是,如何实现与我链接的代码相同的结果,但能够操作填充、描边等属性,并且它必须是一个外部文件,而不仅仅是嵌入在html中的内联svg代码。

如果有人能向我展示正确的方法,我将不胜感激。谢谢。


编辑:

我成功地通过在.svg文件本身中添加CSS来做到这一点。它必须紧接着svg开放标签后面。

<svg ...>
<style type="text/css" media="screen">  
    <![CDATA[      g {          fill: yellow;          stroke: black;          stroke-width: 1;        transition: fill 1s linear 0s;    }    g:hover {        fill: blue;    }    ]]>  
</style> 
<g>
    <path ...>
</g>
</svg>

如果不将其作为object插入到HTML中,它是无法工作的。

<object data="decho.svg" type="image/svg+xml">

希望这对未来寻找像我这样的答案的人有所帮助。这就是帮助我的http://www.hongkiat.com/blog/scalable-vector-graphic-css-styling/


你需要使用JavaScript获取对象文档,然后操作它的DOM,你也可以仅使用CSS来完成。 - Robert Longson
感谢您的回答。我一直在阅读关于可以将CSS直接添加到SVG文件中,您认为这是解决问题的好方法吗? - decho
1
你有办法使用CSS操作SVG尺寸吗? 我不确定是否可能,因为我在网上没有找到这样做的方法。我正在将SVG代码嵌入主页面中的HTML文件中。 - j4v1
@j4v1 如果您查看我的回答中的链接,有两种可能的方法可以使用CSS操纵SVG内部。一种方法是将所有的SVG转换为字体,然后使用font-size和:hover伪类进行操作。另一种方法是将SVG加载到页面顶部作为SVG定义,然后呈现它们为<svg class="blah"><use ...link here></></>,然后使用您的类.blah {...}进行样式设置。 - Robot
这回答您的问题了吗?如何使用外部CSS样式化SVG? - MayeulC
4个回答

29

在我看来,SVG最大的缺陷是沙盒化

SVG文件被沙盒化:它们在自己的文档中,这就是为什么典型的 'fill:' 样式不会应用的原因。同样,您在SVG中编写的CSS将不会应用于站点的其余部分。

直接向SVG添加CSS:不是一个好的解决方案,因为您将最终在使用的每个SVG中重新编写CSS。

真正的解决方案:一个“图标系统”。SVG字体或SVG精灵。了解更多信息在这里

不透明度有效的原因:不透明度应用于SVG对象/框架本身,而不是SVG的内容(这些内容是无法访问的)。

我还应该指出,无论您如何加载这些SVG,内联、通过引用、在对象中、作为背景,都无法进入沙盒。这就是将它们转换成字体或使用精灵进行悬停、聚焦和其他效果/转换所必需的原因。


只要SVG不包含填充,并且CSS中没有使用任何父选择器(影子DOM边界),就可以实现。 - Ben Crook
1
是的,如果我们想要用CSS控制SVG,它会强制我们将SVG包含在HTML中-迫使我们打破内容/语义和图形或样式之间的分离。我想知道为什么。好的,有Ben的解决方案-我可能会开始使用。然而,我所考虑的是通过img[src]基本方式包含SVG。 - Rolf
2
这个答案不再完全正确。您可以通过 <symbol><use> 包含和样式化外部文件。请参阅 Ben Crook 的回答 - totymedli

17

只要SVG文件与网页在同一个域名下(感谢@FabienSnauwaert),且SVG文件本身没有定义填充颜色,同时你的CSS样式表中没有包含父级选择器,那么就可以实现这一效果。例如:

我有以下文件:

  • icon-sprite.svg(我的外部SVG精灵图)
  • buttons.scss
  • test.html

icon-sprite.svg

为了清晰起见,我省略了其他SVG文件。

<svg xmlns="http://www.w3.org/2000/svg" style="width:0;height:0;visibility:hidden;">
    <symbol viewBox="0 0 1500 828" id="icon-arrow-3pt-down">
        <title>arrow-3pt-down</title>
        <path d="M1500 0H0l738.9 827.7z"/>
    </symbol>
</svg>

test.html

<button class="button--large">
    Large button
    <svg class="svg" width="20px" height="20px">
        <use xlink:href="icon-sprite.svg#icon-arrow-3pt-down"></use>
    </svg>
</button>

buttons.scss

.svg {
    fill: red;
}

如果我使用 body .svg,由于影子 DOM 边界,这将无法工作。

SVG 外部 CSS 样式

有关更多信息,请查看此 CSS Tricks 文章


1
@Rolf 我认为SVG片段与我上面提到的不同,那似乎是用于将SVG的一小部分作为CSS背景或放在图像标签内。https://css-tricks.com/svg-fragment-identifiers-work/ 解释得很好,尽管我只是粗略地阅读了一下。 - Ben Crook
1
伟大的解决方案,适用于所有Firefox、Chrome和Safari。注意!尽管xlink:href已被弃用,在Safari中,引用仍必须使用xlink:href属性-仅使用href将导致图像无法加载。(截至Safari 12.0.2发布此文) - Fabien Snauwaert
3
顺便提一下,SVG不支持 alt 属性。另一种选择是使用这个:role="img" aria-label="[title + description]" - Fabien Snauwaert
1
为了使此工作正常,SVG 必须与托管页面在同一域中。(因此,如果您的网站是 example.org,并且您将 SVG 托管在 cdn.example.org 上,那么就无法使用。) 此处有记录:https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use:“出于安全原因,浏览器可以在 use 元素上应用同源策略,并可能拒绝在 href 属性中加载跨源 URL”,这实际上是目前所有三大浏览器发生的情况。(最终使用简单的 <img> 来包含 SVG 并创建 SVG 文件的变体。) - Fabien Snauwaert
1
@FabienSnauwaert 很好的发现,我没有考虑到那种情况。由于SVG可能容易受到跨站脚本攻击,因此拒绝它是有道理的。我已经把这个加入到答案中了,谢谢。 - Ben Crook
显示剩余5条评论

5

最近我遇到了这个问题。尽管由于某种随意的原因,SVG不是DOM的一部分,但你可以通过一些javascript将它们移动到DOM中

<object type="image/svg+xml" data="illustration.svg"
onload="this.parentNode.replaceChild(this.contentDocument.documentElement, this);">
</object>

加载完成后,它将使用内联<svg>替换<object>。如果禁用javascript,则会回退到<object>标签,并且svg不会被主题化。在我的情况下,样式是为一个由javascript控制的黑暗主题而设计的,因此正确的回退意味着没有主题问题。

其他考虑的选项(xlink是精灵的好选择):

  • 使用外部库在DOM内部加载svg(上述js非常简单)
  • 使用svg滤镜进行颜色键控。这使得svg更加复杂,难以编辑,可能需要更多资源来执行过滤,并且不太灵活。

请注意,我不确定安全性方面的影响,请将其保存在您控制的文件中。


这是迄今为止最好的解决方案,对我起了作用。谢谢! - Albos Hajdari

0

很遗憾,Web标准中没有内置的功能可以实现这一点。SVG符号是一个选项,但不适用于托管在CDN上的文件。此外,您需要确保正确定义SVG文件以使用<use>标记。

我创建了一个名为svg-loader的库,使其更容易实现。它使用JavaScript,但仅有3kb,并且异步加载,因此对性能的影响可以忽略不计。它是即插即用的,所以您只需要包含<script>标记即可。

这里是一个Codepen示例


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