SVG图像如何通过CSS更改样式

747

HTML

<img src="logo.svg" alt="Logo" class="logo-img">

层叠样式表(CSS)

.logo-img path {
  fill: #000;
}

以上SVG加载并且本地的 fill:#fff ,但是当我使用上面的 CSS 尝试将其更改为黑色时,它没有改变,这是我第一次操作SVG,不确定为什么它不起作用。


75
你不能通过那种方式影响SVG图像...只能影响内联的SVG元素。 - Paulie_D
请查看我的答案,以了解如何使用SVG和CSS的内容。https://dev59.com/S2ct5IYBdhLWcg3wmOZN#50728869 - Benjamin
3
https://css-tricks.com/change-color-of-svg-on-hover/ - polRk
如果我使用“fill: red”,我可以看到它起作用。.logo-img { fill: #000; }试一下。 - Musfiq Shanta
显示剩余2条评论
27个回答

310

7
除了内部网站外,其他都无法使用。 - Henrik Vendelbo
25
截至2016年5月29日,全球支持率为89%。 - Gajus
2
这是一个非常棒的解决方案,适用于像这里描述的情况,其中在CSS中使用除data uri之外的任何东西都有点麻烦。谢谢! - Gark Garcia
6
无法运行,提示“mask”是“无效的属性值”。我正在Chrome中进行测试。 - mikasa
5
这很有效!我在 div 内添加了 <img src="logo.svg" style="opacity:0" /> 以获得正确的 div 尺寸。 - Shanimal
显示剩余9条评论

267

最近我尝试的一个方案在Edge浏览器上显示的颜色与其他浏览器不同。 - Julix
6
这在大多数浏览器中都有效,但我在IOS-Safari浏览器中遇到了一些问题。 - Simon Ludwig
4
如何找到给定颜色代码的四个值? - Utkarsh
23
这个有效。使用颜色代码生成过滤器 https://codepen.io/sosuke/pen/Pjoqqp?__cf_chl_jschl_tk__=ecc0b72797ae71bc009d6322e3e470773936b386-1604211766-0-ASpz720gXnc6Ej0vzlgY9-KLmlPkldgcOx1wAmGTUCjLZLOxkArNxpRzZ9m8woL-NGmP9LBGVPws8UxMJZrR7O1qFH6QkKtrGVPw6StRnXiK1XTQR_nY905r0XobAG2nOmyC6Zq8mdyPDp1MyHD7JodJUXCRViXhtmLmRVE_-JGarVJRlxs6k3DzAOQQEJewfp00DjhlD0mxr8ZKpk2yq6IPTZZQ52XYxh26FC5MxLHhs7LuAwhtolmDZyp4_IuwRg8I5m-2--MmvGE8CCqjRWrkE85zgkMXPlOqcZtppRpZhn6Uz9DZAuKheHwVBb0ySIhFYG92bvQOgiKX0TTswB1SHgOLIeqktuyUaAgxI_h - mohit uprim
@funky-nd 不,说实话我从来没有因为 CSS 而遇到过性能问题。 - tlt
显示剩余3条评论

223
如果你的目标只是改变logo的颜色,而且不一定需要使用CSS,那么不要像之前的回答建议的那样使用JavaScript或jQuery。
为了精确回答原始问题,请按照以下步骤操作:
1. 在文本编辑器中打开你的logo.svg。 2. 查找fill: #fff并将其替换为fill: #000
例如,在文本编辑器中打开你的logo.svg时,它可能会看起来像这样:
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
  <path d="M0 0h24v24H0z" fill="none"/>
  <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" fill="#fff"/>
</svg>

...只需更改填充颜色并保存即可。


9
如果没有“填充”,您可以将其添加到pathcircle项中,例如<path fill="#777777" d="m129.774,74.409c-5.523,... - SaeX
4
如果我的标志在页眉上是一种颜色,在页脚上是另一种颜色,会怎样呢? - rubens.lopes
63
你可以使用fill="currentColor",然后在父元素上使用color。参考链接:https://css-tricks.com/cascading-svg-fill-color/ - serge
101
这显然是可能的,但不是一个有用的答案。 - Timmmm
2
@Timmmm,“currentColor”的方式实际上非常好。 - Andrei Ardelean
显示剩余4条评论

81
如果您想要一种动态颜色,又不想使用 JavaScript 或内联 SVG,请使用 CSS 变量。适用于 Chrome、Firefox 和 Safari。编辑:还有 Edge。
<svg>
    <use href="logo.svg" style="--color_fill: #000;"></use>
</svg>

在您的SVG中,将任何出现 style="fill: #000" 的地方替换为 style="fill: var(--color_fill)"


8
在SVG 2中似乎已经被弃用 - vsync
12
@northamerican- 将其他stackoverflow答案链接作为“证据”是无关紧要的。任何人都可以在该平台上编写任何内容。MDN:“该功能已从Web标准中删除。尽管某些浏览器仍可能支持它,但正在被淘汰的过程中。” - vsync
12
看起来 xlink:href 已经被 href 取代,所以这个应该仍然可以工作。 - Benjamin Intal
6
@BenjaminIntal 在 Chrome 中,href 似乎对我不起作用。 - Ben Winding
6
看起来很有希望,但是不幸的是它无法加载这张图片。在控制台中也没有错误消息。我正在使用Firefox 78.4 esr。 - RayLuo
显示剩余7条评论

43

编辑您的SVG文件,将 fill="currentColor" 添加到svg标记中,并确保从文件中删除任何其他填充属性。

例如:


<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 139.435269383854" id="img" fill="currentColor">...
</svg>

需要注意的是,currentColor 是一个关键字(而不是在使用中的固定颜色)。

之后,您可以通过设置元素或其父元素的 color 属性来使用 CSS 修改颜色。

示例:

.div-with-svg-inside {
    color: red;
}

我忘了说,你必须以这种方式插入SVG:

<svg>
   <use xlink:href='/assets/file.svg#img' href="/assets/file.svg#img"></use>
</svg>

如果图像来自某个变量,则

<svg>
  <use [attr.xlink:href]="somevariable + '#img'" [attr.href]="somevariable + '#img'"></use>
</svg>

Note that `#img` is the id of the `svg` tag inside svg file. Also note `xlink:href` has been deprecated instead you should use `href` or use can use both to support older browser versions.

Another way of doing it: [https://css-tricks.com/cascading-svg-fill-color/][1]


  [1]: https://css-tricks.com/cascading-svg-fill-color/

3
xlink:href 是一个已经被弃用的功能,不应该被使用。https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/xlink:href - kano
需要将CSS属性中的颜色更改为fill: red。 - LogGurkha
截至2022年8月,建议使用href而不是已被弃用的xlink:href,如Kano所述。 - Davi Mello
非常棒的答案,谢谢!使用[]变量的答案在Angular 13中完美运行。 - Cyril Duchon-Doris
我无法正确地完成它,你能否请提供一个有效的 fiddle 示例?这将不胜感激。我正在尝试从外部链接加载 svg,像这样:<svg viewBox="0 0 200 200"> <use fill="blue" href="https://cdn.jsdelivr.net/gh/instanano/apparatus/test111.svg#test111"> </use></svg> - Dheeraj Kumar
显示剩余2条评论

42

建议选择您的颜色,并转到此代码片段https://codepen.io/sosuke/pen/Pjoqqp,它可以将 HEX 转换为 CSS 滤镜,例如:#64D7D6

等同于:

filter: invert(88%) sepia(21%) saturate(935%) hue-rotate(123deg) brightness(85%) contrast(97%);

最终片段

.filterit{
width:270px;
filter: invert(88%) sepia(21%) saturate(935%) hue-rotate(123deg) brightness(85%) contrast(97%);
}
<img src="https://www.flaticon.com/svg/static/icons/svg/1389/1389029.svg"
class="filterit

/>


1
这真的帮助了我在无法更改标记的情况下。 - penguinflip
即使使用brightness(0)saturate(100%),结果几乎从未是我想要的,因此尽管付出了很多工作,但结果远非应该如此。 - e11world
@e11world SVG文件本身不应该有颜色,请务必注意。 - Jehad Ahmad Jaghoub
我只是想将我的深色主题反转,这正是我想要的。谢谢。 - Anupam

41

您需要首先将SVG注入到HTML DOM中。

有一个名为SVGInject的开源库可以为您完成此操作。它使用onload属性触发注入。

以下是使用SVGInject的最简示例:

<html>
  <head>
    <script src="svg-inject.min.js"></script>
  </head>
  <body>
    <img src="image.svg" onload="SVGInject(this)" />
  </body>
</html>

图片加载完成后,onload="SVGInject(this)"会触发注入过程,<img>元素将被替换为src属性提供的SVG文件内容。

它解决了几个与SVG注入相关的问题:

  1. SVG可以在注入完成之前隐藏。如果在加载期间已经应用了样式,否则会导致短暂的“未成样式的内容闪烁”,这一点很重要。

  2. <img>元素会自动注入。如果您动态添加SVG,则无需担心再次调用注入函数。

  3. 每个ID中都添加一个随机字符串,避免了在文档中多次注入相同的ID,如果同一个SVG文件被注入多次则尤为重要。

SVGInject是纯JavaScript编写的,适用于支持SVG的所有浏览器。

免责声明:我是SVGInject的联合作者


6
这是最直接的答案。我在Chrome、Firefox和Edge中进行了测试,它能完美地运行。 - Sébastien Lorion
11
这是一个可行的解决方案,但我认为“最直接”的说法有些牵强。 - Parker Kemp

25

使用滤镜转换为任何颜色。

我最近发现了这个解决方案,希望有人能够使用它。 由于该解决方案使用了滤镜,因此可以与任何类型的图像一起使用,不仅限于 svg。

如果您有一个单色图像,只想更改其颜色,您可以使用一些滤镜来实现。当然,它也适用于多色图像,但您无法针对特定颜色进行操作,只能操作整个图像。

这些滤镜来自于在如何使用 CSS 滤镜将黑色转换为任何给定颜色中提出的脚本。如果要将白色更改为任何颜色,则可以调整每个滤镜中的反转值。

.startAsBlack{
  display: inline-block;
  width: 50px;
  height: 50px;
  background: black;
}

.black-green{
  filter: invert(43%) sepia(96%) saturate(1237%) hue-rotate(88deg) brightness(128%) contrast(119%);
}

.black-red{
  filter: invert(37%) sepia(93%) saturate(7471%) hue-rotate(356deg) brightness(91%) contrast(135%);
}

.black-blue{
  filter: invert(12%) sepia(83%) saturate(5841%) hue-rotate(244deg) brightness(87%) contrast(153%);
}

.black-purple{
  filter: invert(18%) sepia(98%) saturate(2657%) hue-rotate(289deg) brightness(121%) contrast(140%);
}
Black to any color: <br/>
<div class="startAsBlack black-green"></div>
<div class="startAsBlack black-red"></div>
<div class="startAsBlack black-blue"></div>
<div class="startAsBlack black-purple"></div>


1
这个 filter 很有效!如果你有 HEX 颜色 并想从中生成滤镜颜色,请使用 Codepen 的 CSS 滤镜生成器。生成的滤镜颜色适用于最初为黑色的颜色。如果你有一个最初为白色的颜色,你可以增加生成的滤镜颜色的亮度来达到目标颜色。 - Berkin Sansal

24

本答案基于答案https://stackoverflow.com/a/24933495/3890888,但使用了该脚本的纯JavaScript版本。

您需要将SVG转换为内联SVG。您可以通过向图像添加一个类svg来使用此脚本:

/*
 * Replace all SVG images with inline SVG
 */
document.querySelectorAll('img.svg').forEach(function(img){
    var imgID = img.id;
    var imgClass = img.className;
    var imgURL = img.src;

    fetch(imgURL).then(function(response) {
        return response.text();
    }).then(function(text){

        var parser = new DOMParser();
        var xmlDoc = parser.parseFromString(text, "text/xml");

        // Get the SVG tag, ignore the rest
        var svg = xmlDoc.getElementsByTagName('svg')[0];

        // Add replaced image's ID to the new SVG
        if(typeof imgID !== 'undefined') {
            svg.setAttribute('id', imgID);
        }
        // Add replaced image's classes to the new SVG
        if(typeof imgClass !== 'undefined') {
            svg.setAttribute('class', imgClass+' replaced-svg');
        }

        // Remove any invalid XML tags as per http://validator.w3.org
        svg.removeAttribute('xmlns:a');

        // Check if the viewport is set, if the viewport is not set the SVG wont't scale.
        if(!svg.getAttribute('viewBox') && svg.getAttribute('height') && svg.getAttribute('width')) {
            svg.setAttribute('viewBox', '0 0 ' + svg.getAttribute('height') + ' ' + svg.getAttribute('width'))
        }

        // Replace image with new SVG
        img.parentNode.replaceChild(svg, img);

    });

});

那么,现在如果你执行以下操作:

.logo-img path {
  fill: #000;
}

也许可以这样做:
.logo-img path {
  background-color: #000;
}

JSFiddle: http://jsfiddle.net/erxu0dzz/1/


1
太好了..有效。此外,如果我们的页面有多个SVG,则需要将获取块放入IIFE中。 - Sandeep Sharma
1
太好了! 与ES6兼容良好。如果您不关心IE 9,甚至可以使用:parser.parseFromString(text,“image/svg+xml”); - ChristoKiwi
在iOS 9.3.5的UIWebView中无法工作。我认为这可能是由于使用了在Safari 10.1中添加的fetch导致的(https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)。jQuery版本可以正常工作。 - mariaines

17
为什么不使用你的SVG图像创建Web字体,将Web字体导入CSS中,然后只需使用CSS颜色属性更改字形的颜色?无需JavaScript。

6
如果你的 SVG 包含多个不同颜色的元素,那么这种解决方案就会变得非常 hacky(即多个元素相互穿插)。 - kakaja
1
@kakaja 这仅适用于只有一种颜色的矢量图像的解决方案。有关更多详细信息,请参阅bpulecio的答案。 - gringo
2
因为图标不是文本。字体用于文本。SVG 用于图标。 - Lazar Ljubenović
2
@LazarLjubenović - 从技术上讲,文本由符号组成,图标也是符号,因此许多人使用图标字体没有问题。这就像创建“另一种”文本语言一样。汉语也使用“图标”而不是字母,使用图标作为“文本”在人类中并不罕见。 - vsync
7
虽然这听起来是一个有趣的解决方案,但我真的建议将答案详细阐述成更像是“如何”而不是“为什么不”。 - YakovL
显示剩余3条评论

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