723

html

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

css

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

The above svg loads and is natively fill: #fff but when I use the above css to try change it to black it doesn't change, this is my first time playing with SVG and I am not sure why it's not working.

Paulie_D
  • 107,962
  • 13
  • 142
  • 161
ngplayground
  • 20,365
  • 36
  • 94
  • 173
  • 2
    Possible duplicate of [How to change color of SVG image using CSS (jQuery SVG image replacement)?](http://stackoverflow.com/questions/11978995/how-to-change-color-of-svg-image-using-css-jquery-svg-image-replacement) – Icarus Jan 31 '17 at 09:16
  • Check my answer here to use contents of SVG and CSS. https://stackoverflow.com/questions/11978995/how-to-change-color-of-svg-image-using-css-jquery-svg-image-replacement/50728869#50728869 – Benjamin Jun 06 '18 at 20:21
  • 3
    https://css-tricks.com/change-color-of-svg-on-hover/ – polRk Nov 15 '19 at 18:40
  • if i use "fill: red" I see it work. .logo-img { fill: #000; } Try it – Musfiq Shanta May 13 '22 at 17:52
  • Best solution in React. Look at "Using an SVG as a component " in https://blog.logrocket.com/how-to-use-svgs-in-react/ – Mounika Bathina Oct 13 '22 at 15:15
  • In modern browsers supporting Web Components you can create your own ```` Web Component with 7 lines of JavaScript code. Blog at: [Dev.to](https://dev.to/dannyengelman/load-file-web-component-add-external-content-to-the-dom-1nd) – Danny '365CSI' Engelman Aug 24 '23 at 08:13

27 Answers27

302

You could set your SVG as a mask. That way setting a background-color would act as your fill color.

HTML

<div class="logo"></div>

CSS

.logo {
  background-color: red;
  -webkit-mask: url(logo.svg) no-repeat center;
  mask: url(logo.svg) no-repeat center;
}

JSFiddle: https://jsfiddle.net/KuhlTime/2j8exgcb/
MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/mask

Please check whether your browser supports this feature: https://caniuse.com/#search=mask

André Kuhlmann
  • 4,378
  • 3
  • 23
  • 42
  • 7
    So for anything but internal website unusable. – Henrik Vendelbo May 21 '17 at 13:18
  • 25
    89% global support as of 29th May 2016. – Gajus May 29 '17 at 12:06
  • Nice but probably not useful for animated svgs. – Johann Sep 22 '18 at 12:26
  • 2
    This is an amazing solution for situations like the one described in [here](https://css-tricks.com/lodge/svg/09-svg-data-uris/#comment-1586344), where using anything other than data uris in css is a bit of a pain. Thanks! – Gark Garcia Jan 19 '19 at 13:15
  • 6
    its not working. it says `mask` is an `invalid property value`. i am testing this in chrome. – mikasa Jan 28 '20 at 18:42
  • 5
    This works great! I added `` inside the div for correct `div` dimensions. – Shanimal Mar 19 '20 at 23:36
  • @Eren555 what version of chrome are you using? – André Kuhlmann Apr 17 '20 at 08:31
  • This does not seem to work for me in Chrome Version 83.0.4103.97 it just flashes red and then back to black. – MadMac Jun 10 '20 at 04:16
  • 1
    @MadMac I am running the same version of Chrome, but I wasn't able to replicate that behaviour. Is it the JSFiddle you tried or your code? – André Kuhlmann Jun 10 '20 at 07:47
  • @AndréKuhlmann My mistake, I was using existing code and had a src attribute in the img element pointing to the svg also. It now works fine. Thanks. – MadMac Jun 10 '20 at 21:23
  • Sadly, we will have cors issue if use this approach – Minh Thành Aug 18 '21 at 03:16
  • 1
    OK, so my problem was CORS policy - check that ESPECIALLY when working on local/localhost :D – jave.web Oct 22 '21 at 01:26
  • 1
    @mikasa - Chrome supports only prefixed version `-webkit-mask` (2021-10) prefix support is **strong** though: Chrome, Edge, Safari, Opera all use that :-) Firefox is only major that supports non-prefixed version`mask`. The prefixed version also goes for other sub-properties like `-webkit-mask-image` – jave.web Oct 22 '21 at 13:46
255

Try pure CSS:

.logo-img {
  /* to black */
  filter: invert(1);
  /* or to blue */
  filter: invert(0.5) sepia(1) saturate(5) hue-rotate(175deg);
}

more info in this article https://blog.union.io/code/2017/08/10/img-svg-fill/

Guy
  • 12,488
  • 16
  • 79
  • 119
Feri
  • 2,709
  • 1
  • 12
  • 7
  • Was getting a different color on Edge than on other browsers with one of my attempts recently. – Julix Mar 08 '19 at 18:23
  • 6
    This works in the most browser but i had some issues with IOS-Safari browser. – Simon Ludwig Mar 23 '19 at 11:43
  • 3
    How to find the values of all four for a given colour code? – Utkarsh Jul 09 '20 at 11:20
  • 18
    This works. To generate the filter using color code https://codepen.io/sosuke/pen/Pjoqqp?__cf_chl_jschl_tk__=ecc0b72797ae71bc009d6322e3e470773936b386-1604211766-0-ASpz720gXnc6Ej0vzlgY9-KLmlPkldgcOx1wAmGTUCjLZLOxkArNxpRzZ9m8woL-NGmP9LBGVPws8UxMJZrR7O1qFH6QkKtrGVPw6StRnXiK1XTQR_nY905r0XobAG2nOmyC6Zq8mdyPDp1MyHD7JLodJUXCRViXhtmLmRVE_-JGarVJRlxs6k3DzAOQQEJewfp00DjhlD0mxr8ZKpk2yq6IPTZZQ52XYxh26FC5MxLHhs7LuAwhtolmDZyp4_IuwRg8I5m-2--MmvGE8CCqjRWrkE85zgkMXPlOqcZtppRpZhn6Uz9DZAuKheHwVBb0ySIhFYG92bvQOgiKX0TTswB1SHgOLIeqktuyUaAgxI_h – mohit uprim Nov 01 '20 at 07:27
  • @funky-nd no, and i've never seen a performance problem due to css tbh. – tlt Mar 17 '21 at 09:57
  • how do I make it white? – chovy Feb 02 '22 at 18:49
  • @chovy try this `filter: brightness(0) saturate(100%) invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(102%) contrast(102%);` – Feri Feb 04 '22 at 10:17
  • @chovy to make white `filter: brightness(0) invert(1);` Brightness(0) makes all image black, except transparent parts, which remain transparent, invert(1) makes the black parts white. seen [here](https://stackoverflow.com/questions/24224112/css-filter-make-color-image-with-transparency-white) – Fanky Oct 06 '22 at 10:14
221

If your goal is just to change the color of the logo, and you don't necessarily NEED to use CSS, then don't use javascript or jquery as was suggested by some previous answers.

To precisely answer the original question, just:

  1. Open your logo.svg in a text editor.

  2. look for fill: #fff and replace it with fill: #000

For example, your logo.svg might look like this when opened in a text editor:

<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>

... just change the fill and save.

Rowe Morehouse
  • 4,451
  • 3
  • 28
  • 28
  • 9
    ... and if there is no "fill", you can just add it to the `path` or `circle` items like ` – SaeX Jun 01 '16 at 09:55
  • 4
    what if my logo has one color on header and another color on footer? – rubens.lopes Jun 30 '17 at 13:44
  • .@ruben.lopes two different files, or two different inlines would be simplest – Rowe Morehouse Jun 30 '17 at 17:41
  • 63
    you can use also the `fill="currentColor"` then use the `color` on the parent element https://css-tricks.com/cascading-svg-fill-color/ – serge Nov 23 '17 at 14:45
  • 98
    This is obviously possible and not really a helpful answer. – Timmmm Dec 19 '19 at 16:54
  • 2
    @Timmmm The `currentColor` way is very good actually. – Andrei Ardelean Dec 30 '21 at 22:44
  • I was referring to the main answer. Modesto made a full answer for `currentColor`. – Timmmm Dec 31 '21 at 17:32
  • @serge the main question is using the img tag, not using inline svg, what if I'm using it to change the color when hovering? – John Balvin Arias Aug 09 '22 at 23:03
  • Beware, when using masks, it can conflict with other elements like fixed or sticky elements where the mask appears on top of those elements even if they are placed before the element with the mask. Setting z-index on those elements may fix the problem but tinkering with z-indexes is not my favorite passtime. Example: https://drive.google.com/file/d/1DV9JI1yrxN0Jg2XrJcXp5Q6vb4lNpymK – Dave de Jong Feb 16 '23 at 14:51
81

If you want a dynamic color, do not want to use javascript and do not want an inline SVG, use a CSS variable. Works in Chrome, Firefox and Safari. edit: and Edge

<svg>
    <use href="logo.svg" style="--color_fill: #000;"></use>
</svg>

In your SVG, replace any instances of style="fill: #000" with style="fill: var(--color_fill)".

northamerican
  • 2,185
  • 1
  • 20
  • 31
  • 1
    Whats the browser support for this – Kevin Goedecke Aug 27 '18 at 12:42
  • 1
    @KevinGoedecke Chrome, Firefox, Safari and Edge – northamerican Aug 27 '18 at 18:56
  • 8
    Seems [deprecated](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href) in *SVG 2* – vsync Sep 08 '18 at 17:06
  • @vsync Safari still requires xlink:href. All other browsers still support it. see: https://stackoverflow.com/a/43962207/552963 – northamerican Sep 14 '18 at 16:49
  • 11
    @northamerican - links to other stackoverflow answers as "proofs" are irrelevant. anybody can write anything on this platform. MDN: *`"This feature has been removed from the Web standards. Though some browsers may still support it, it is in the process of being dropped"`* – vsync Sep 15 '18 at 07:05
  • 12
    It seems that `xlink:href` is deprecated in favor of `href`. So this may still work. – Benjamin Intal Nov 08 '18 at 02:46
  • 6
    @BenjaminIntal `href` doesn't seem to work for me in chrome – Ben Winding Feb 17 '20 at 04:20
  • 1
    `href` worked in place of `xlink:href` for me in chrome, and looking at the spec I don't see why it wouldn't - it seems like the intended use case. It *won't* work though if you're running it from `file://`, has to come from a web server, and if it's coming from a different origin you might run into CORS issues. – tobek Mar 21 '21 at 19:38
  • 6
    Looks promising but, alas it does not load the picture. There is no error message in the console either. I'm using Firefox 78.4 esr. – RayLuo May 06 '21 at 22:31
  • 2
    for me original svg must have defined `xmlns:xlink` and `id`: https://stackoverflow.com/a/29886130/2232320 – mustordont May 17 '21 at 10:54
  • 1
    for clarity on the id, I could do this: `` Where the .svg file has the id specified in the svg tag ` – shawn caza Feb 01 '23 at 05:06
42

Edit your SVG file, add fill="currentColor" to svg tag and make sure to remove any other fill property from the file.

For example:

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

Note that currentColor is a keyword (not a fixed color in use).

After that, you can change the color using CSS, by setting the color property of the element or from it's parent.

Example:

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

I forgot to say, you must insert the SVG this way:

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

if image is coming from some variable then

<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/
WasiF
  • 26,101
  • 16
  • 120
  • 128
Modesto
  • 569
  • 4
  • 8
  • 3
    `xlink:href` is a deprecated feature and **should not be used** https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href – kano Dec 25 '20 at 21:08
  • Need to change the fill: red instead of a color CSS property. – LogGurkha Oct 05 '21 at 10:03
  • As of August 2022 it is recommended to use `href` instead of `xlink:href` that got deprecated as mentioned by [Kano](https://stackoverflow.com/users/2803743/kano). – Davi Mello Aug 23 '22 at 14:59
  • Awesome answer, thanks ! The answer with [] variables works perfect in angular 13 – Cyril Duchon-Doris Aug 31 '22 at 09:45
  • I am not able to do it properly, can you please give a working fiddle example? It would be highly appreciated. I am trying to load svg from external link like this, ` ` – Dheeraj Kumar Sep 01 '22 at 06:00
  • The namespaced **`xlink:href` is still required by a lot of applications** like desktop graphic apps, image previewers (with less capable svg 1.x svg support). Including both `href` and `xlink:href` as well as `xmlns:xlink="http://www.w3.org/1999/xlink"` for the parent svg provides the **best compatibility for standalone svgs**. Besides the support for `xlink:href` is flawless: [mdn docs compatibility](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href#browser_compatibility) [caniuse](https://caniuse.com/?search=xlink%3Ahref). So it **won't solve any problems!** – herrstrietzel Dec 04 '22 at 01:16
  • The fact that they introduced an editable image format, then made it this complicated to edit anything in it, blows my mind, and is quite typical from the consortium. Why does it HAVE to be inline? Why does it HAVE to be loaded inside of an SVG tag?? What is this mess? – beliha Aug 03 '23 at 13:37
40

You will first have to inject the SVG into the HTML DOM.

There is an open source library called SVGInject that does this for you. It uses the onload attribute to trigger the injection.

Here is a minimal example using SVGInject:

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

After the image is loaded the onload="SVGInject(this) will trigger the injection and the <img> element will be replaced by the contents of the SVG file provided in the src attribute.

It solves several issues with SVG injection:

  1. SVGs can be hidden until injection has finished. This is important if a style is already applied during load time, which would otherwise cause a brief "unstyled content flash".

  2. The <img> elements inject themselves automatically. If you add SVGs dynamically, you don't have to worry about calling the injection function again.

  3. A random string is added to each ID in the SVG to avoid having the same ID multiple times in the document if an SVG is injected more than once.

SVGInject is plain Javascript and works with all browsers that support SVG.

Disclaimer: I am the co-author of SVGInject

Waruyama
  • 3,267
  • 1
  • 32
  • 42
40

I suggest to select your color , and go to this pen https://codepen.io/sosuke/pen/Pjoqqp it will convert HEX to css filter eg:#64D7D6

equal

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

the final snippet

.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

/>
Jehad Ahmad Jaghoub
  • 1,225
  • 14
  • 22
24

This answer is based on answer https://stackoverflow.com/a/24933495/3890888 but with a plain JavaScript version of the script used there.

You need to make the SVG to be an inline SVG. You can make use of this script, by adding a class svg to the image:

/*
 * 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);

    });

});

And then, now if you do:

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

Or may be:

.logo-img path {
  background-color: #000;
}

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

Community
  • 1
  • 1
Sebastian
  • 1,710
  • 2
  • 16
  • 28
  • 1
    Great.. works. in addition if our page have multiple svgs then we will need to put fetch block into the IIFE. – Sandeep Sharma Apr 16 '17 at 07:54
  • 1
    Great! Works well with ES6. If you don't care about IE 9 you can even use: `parser.parseFromString(text, "image/svg+xml");` – ChristoKiwi Jul 04 '17 at 23:16
  • Doesn't work in a UIWebView on iOS 9.3.5. I *think* it might be due to the use of `fetch` which was added to Safari in 10.1 (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). jQuery version above does work. – mariaines Apr 26 '18 at 18:35
24

Use filters to transform to any color.

I recently found this solution, and hope somebody might be able to use it. Since the solution uses filters, it can be used with any type of image. Not just svg.

If you have a single-color image that you just want to change the color of, you can do this with the help of some filters. It works on multicolor images as well of course, but you can't target a specific color. Only the whole image.

The filters came from the script proposed in How to transform black into any given color using only CSS filters If you want to change white to any color, you can adjust the invert value in each filter.

.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>
JasperZelf
  • 2,731
  • 1
  • 22
  • 34
  • 1
    This `filter` works! If you have **HEX color** and want to generate filter color from it, use the [CSS filter generator from Codepen](https://codepen.io/sosuke/pen/Pjoqqp). The generated filter color works for colors which are initially black. If you have a color which is initially white, you can increase brightness of generated filter color to achieve target color. – Berkin Sansal Feb 02 '22 at 13:02
17

Why not create a webfont with your svg image or images, import the webfont in the css and then just change the color of the glyph using the css color attribute? No javascript needed

gringo
  • 255
  • 2
  • 4
  • 6
    If your svg has several elements of different colors, this solution becomes very hacky (several elements interposed). – kakaja Jul 20 '17 at 11:29
  • 1
    @kakaja This is a solution only for vector images that have 1 color in them. see bpulecio's answer for more details – gringo Jul 21 '17 at 07:53
  • 2
    Because icon is not text. Fonts are for text. Svgs are for icons. – Lazar Ljubenović May 16 '18 at 14:09
  • 2
    @LazarLjubenović - technically text is made of characters which are symbols, and icons are also symbols, so this is why many do not have problem using icon-fonts. it's just like creating "another" textual language. Mandarin uses "icons" and not letters also, it's not uncommon in humanity to use icons as "text" – vsync Sep 08 '18 at 17:04
  • @vsync Many do not have a problem with using icons because it's what Bootstrap does and what w3schools as a top Google result. Icons are not characters, they're inline images which enhance the content. – Lazar Ljubenović Sep 08 '18 at 18:31
  • 7
    while this sounds as an interesting solution, I really recommend to elaborate the answer into something more like "how to" instead of "why not" – YakovL Mar 20 '19 at 12:53
  • If all your icons can be mapped to appropriate unicode characters I would say ✓ to using an icon font. – KernelDeimos Jun 08 '20 at 17:10
17

Simple..

You can use this code:

<svg class="logo">
  <use xlink:href="../../static/icons/logo.svg#Capa_1"></use>
</svg>

First specify the path of svg and then write it's ID, In this case "Capa_1". You can get the ID of svg by opening it in any editor.

In css:

.logo {
  fill: red;
}
Hamza Jamal
  • 189
  • 1
  • 3
15

The answer from @Praveen is solid.

I couldn't get it to respond in my work, so I made a jquery hover function for it.

CSS

.svg path {
   transition:0.3s all !important;
}

JS / JQuery

// code from above wrapped into a function
replaceSVG();

// hover function
// hover over an element, and find the SVG that you want to change
$('.element').hover(function() {
    var el = $(this);
    var svg = el.find('svg path');
    svg.attr('fill', '#CCC');
}, function() {
    var el = $(this);
    var svg = el.find('svg path');
    svg.attr('fill', '#3A3A3A');
});
sleepDrifter
  • 591
  • 4
  • 7
7

If you are just switching the image between the real color and the black-and-white, you can set one selector as:

{filter:none;}

and another as:

{filter:grayscale(100%);}
wcb1
  • 665
  • 1
  • 7
  • 6
5

Since SVG is basically code, you need just contents. I used PHP to obtain content, but you can use whatever you want.

<?php
$content    = file_get_contents($pathToSVG);
?>

Then, I've printed content "as is" inside a div container

<div class="fill-class"><?php echo $content;?></div>

To finnaly set rule to container's SVG childs on CSS

.fill-class > svg { 
    fill: orange;
}

I got this results with a material icon SVG:

Mozilla Firefox 59.0.2 (64-bit) Linux

enter image description here

Google Chrome66.0.3359.181 (Build oficial) (64 bits) Linux

enter image description here

Opera 53.0.2907.37 Linux

enter image description here

Benjamin
  • 558
  • 7
  • 15
  • My reason for not doing this is that this prevents the browser to cache the SVG. The alternative is to use an SVG injector mentioned in a few other answers here. The SVG file will still be cached by the browser, and the injected SVG can still be styled with CSS. But I don't downvote you. – Sơn Trần-Nguyễn May 08 '19 at 17:43
  • I understand, but anyway, cache is not mentioned. Best answer have JavaScript code that can be reload (or not) everytime by header expire manipulation or force a hash after filename link.Thanks for do not downvote, but I still believing that my answer solves changing an SVG using CSS fill attribute. – Benjamin May 08 '19 at 20:46
3

To expand on @gringo answer, the Javascript method described in other answers works, but requires the user to download unnecessary image files, and IMO, it bloats your code.

I think a better approach would be to to migrate all 1-color vector graphics to a webfont file. I've used Fort Awesome in the past, and it works great to combine your custom icons/images in SVG format, along with any 3rd party icons you may be using (Font Awesome, Bootstrap icons, etc.) into a single webfont file the user has to download. You can also customize it, so you only include the 3rd party icons you're using. This reduces the number of requests the page has to make, and you're overall page weight, especially if you're already including any 3rd party icons libraries.

If you prefer a more dev oriented option, you could Google "npm svg webfont", and use one of the node modules that's most appropriate for your environment.

Once, you've done either of those two options, then you could easily change the color via CSS, and most likely, you've sped up your site in the process.

bpulecio
  • 78
  • 1
  • 3
  • You should give SVG sprites a try. In my experience, web-fonts have random issues between browser releases. Try this: http://fontastic.me/ - but use the SVG sprite versions - and see what you think. : ) – sheriffderek Feb 20 '18 at 20:35
3

This might be helpful for people using PHP in combination with .svg images that they want to manipulate with CSS.

You can't overwrite properties inside a img tag with CSS. But when the svg source code is embedded in the HTML you surely can. I like to resolve this issue with a require_once function where I include a .svg.php file. It's like importing an image but you can still overwrite styles with CSS!

First include the svg file:

<?php require_once( '/assets/images/my-icon.svg.php' ); ?>

And it includes this icon for example:

<svg xmlns="http://www.w3.org/2000/svg" width="20.666" height="59.084" viewBox="0 0 20.666 59.084"><g transform="translate(-639.749 -3139)"><path d="M648.536,3173.876c0-2.875-1.725-3.8-3.471-3.8-1.683,0-3.49.9-3.49,3.8,0,3,1.786,3.8,3.49,3.8C646.811,3177.676,648.536,3176.769,648.536,3173.876Zm-3.471,2.341c-.883,0-1.437-.513-1.437-2.341,0-1.971.615-2.381,1.437-2.381.862,0,1.438.349,1.438,2.381,0,1.907-.616,2.339-1.438,2.339Z" fill="#142312"/><path d="M653.471,3170.076a1.565,1.565,0,0,0-1.416.9l-6.558,13.888h1.2a1.565,1.565,0,0,0,1.416-.9l6.559-13.887Z" fill="#142312"/><path d="M655.107,3177.263c-1.684,0-3.471.9-3.471,3.8,0,3,1.766,3.8,3.471,3.8,1.745,0,3.49-.9,3.49-3.8C658.6,3178.186,656.851,3177.263,655.107,3177.263Zm0,6.139c-.884,0-1.438-.514-1.438-2.34,0-1.972.617-2.381,1.438-2.381.862,0,1.437.349,1.437,2.381,0,1.909-.616,2.34-1.437,2.34Z" fill="#142312"/><path d="M656.263,3159.023l-1.49-14.063a1.35,1.35,0,0,0,.329-.293,1.319,1.319,0,0,0,.268-1.123l-.753-3.49a1.328,1.328,0,0,0-1.306-1.054h-6.448a1.336,1.336,0,0,0-1.311,1.068l-.71,3.493a1.344,1.344,0,0,0,.276,1.112,1.532,1.532,0,0,0,.283.262l-1.489,14.087c-1.7,1.727-4.153,4.871-4.153,8.638v28.924a1.339,1.339,0,0,0,1.168,1.49,1.357,1.357,0,0,0,.17.01h17.981a1.366,1.366,0,0,0,1.337-1.366v-29.059C660.414,3163.893,657.963,3160.749,656.263,3159.023Zm-8.307-17.349h4.274l.176.815H647.79Zm9.785,43.634v10.1H642.434v-17.253a4.728,4.728,0,0,1-2.028-4.284,4.661,4.661,0,0,1,2.028-4.215v-2c0-3.162,2.581-5.986,3.687-7.059a1.356,1.356,0,0,0,.4-.819l1.542-14.614H652.1l1.545,14.618a1.362,1.362,0,0,0,.4.819c1.109,1.072,3.688,3.9,3.688,7.059v9.153a5.457,5.457,0,0,1,0,8.5Z" fill="#142312"/></g></svg>

Now we can easily change the fill color like this with CSS:

svg path {
  fill: blue;
}

I first tried to solve this problem with file_get_contents() but the solution above is much faster.

Floris
  • 2,727
  • 2
  • 27
  • 47
  • What about `require_once()` is faster than `file_get_contents()`? Because it's a purely local call? – Jeff Dec 15 '21 at 12:38
  • Yes. As far as I know `file_get_contents()` does a GET request and require_once includes it locally. – Floris Dec 16 '21 at 10:02
2

The main problem in your case is that you are importing the svg from an <img> tag which will hide the SVG structure.

You need to use the <svg> tag in conjunction with the <use> to get the desired effect. To make it work, you need to give an id to the path you want to use in the SVG file <path id='myName'...> to then be able to retrieve them from the <use xlink:href="#myName"/> tag. Try the snipped below.

.icon {
  display: inline-block;
  width: 2em;
  height: 2em;
  transition: .5s;
  fill: currentColor;
  stroke-width: 5;
  }
  .icon:hover {
    fill: rgba(255,255,255,0);
    stroke: black;
    stroke-width: 2;
    }

.red {
  color: red;
  }

.blue {
  color: blue;
  }
<svg width="0" height="0">
  <defs>
    <path id="home" d="M100 59.375l-18.75-18.75v-28.125h-12.5v15.625l-18.75-18.75-50 50v3.125h12.5v31.25h31.25v-18.75h12.5v18.75h31.25v-31.25h12.5z"/>
</svg>

  
  <span class="icon red">
          <svg viewbox="0 0 100 100">
            <use xlink:href="#home"/>
          </svg>
        </span>
  
    <span class="icon blue">
          <svg viewbox="0 0 100 100">
            <use xlink:href="#home"/>
          </svg>
        </span>

Note that you can put any URL before the fragment # if you want to load the SVG from an external source (and not embed it into your HTML). Also, usually you do not specify the fill into the CSS. It's better to consider using fill:"currentColor" within the SVG itself. The corresponding element's CSS color value will then be used in place.

Flavien Volken
  • 19,196
  • 12
  • 100
  • 133
1

open the svg icon in your code editor and add a class after the path tag:

<path class'colorToChange' ...

You can add class to svg and change the color like this:

codepen

Hamza Jamal
  • 189
  • 1
  • 3
0

Know this is an old question but recently we came across the same issue, and we solved it from the server side. This is a php specific answer but I am positive that other envs have something similar. instead of using the img tag you render the svg as svg from the get-go.

public static function print_svg($file){
    $iconfile = new \DOMDocument();
    $iconfile->load($file);
    $tag = $iconfile->saveHTML($iconfile->getElementsByTagName('svg')[0]);
    return $tag;
}

now when you render the file you will get complete inline svg

0

For me, my svgs looked different when having them as img and svg. So my solution converts the img to csv, changes styles internally and back to img (although it requires a bit more work), I believe "blob" also has better compatibility than the upvoted answer using "mask".

  let img = yourimgs[0];
  if (img.src.includes(".svg")) {
    var ajax = new XMLHttpRequest();
    ajax.open("GET", img.src, true);
    ajax.send();
    ajax.onload = function (e) {
     
      svg = e.target.responseText;

     
      svgText = "";
      //change your svg-string as youd like, for example
      // replacing the hex color between "{fill:" and ";"
      idx = svg.indexOf("{fill:");
      substr = svg.substr(idx + 6);
      str1 = svg.substr(0, idx + 6);
      str2 = substr.substr(substr.indexOf(";"));
      svgText = str1 + "#ff0000" + str2;
      

      let blob = new Blob([svgText], { type: "image/svg+xml" });
      let url = URL.createObjectURL(blob);
      let image = document.createElement("img");
      image.src = url;
      image.addEventListener("load", () => URL.revokeObjectURL(url), {
        once: true,
      });
      img.replaceWith(image);
    };
  }
Servus
  • 479
  • 3
  • 13
0

Simple JS

Use following short function ImgToSvg which swap img to svg (including class list)

<img src="logo.svg" onload="ImgToSvg(this)" class="logo-img"/>

const ImgToSvg= async (img) => {
  const s = document.createElement('div');
  s.innerHTML = await (await fetch(img.src)).text();
  s.firstChild.classList = img.classList;
  img.replaceWith(s.firstChild)
}
.logo-img {
  fill: yellow;
}
<img onload="ImgToSvg(this)" class="logo-img" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMjk2IiBoZWlnaHQ9IjI5NiIgc3R5bGU9InN0cm9rZTojNTU1NTU1O3N0cm9rZS13aWR0aDoyIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtc2l6ZT0iMTgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGFsaWdubWVudC1iYXNlbGluZT0ibWlkZGxlIiBmb250LWZhbWlseT0ibW9ub3NwYWNlLCBzYW5zLXNlcmlmIiBmaWxsPSIjNTU1NTU1Ij4zMDAmIzIxNTszMDA8L3RleHQ+PC9zdmc+" />

<!-- in this snippet I use dataURI in img src to avoid CORS problems witch reading svg data from external source by js -->

This is improvement of Waruyama answer by providing short js function

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
0

The reason for your CSS not having any effect here is, that you can't control the innards of an SVG embedded via the img tag (as you can read in this or this article).

There are several solutions to this:

a) Embed SVGs with the svg tag

✔️ Most straightforward
❌ SVGs not reusable (at most reusable per HTML file by implementing this)

svg {
    height: 200px;
    width: 200px;
    fill: red;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
            <path
                d="M18.896 0H1.104C.494 0 0 .494 0 1.104v17.793C0 19.506.494 20 1.104 20h9.58v-7.745H8.076V9.237h2.606V7.01c0-2.583 1.578-3.99 3.883-3.99 1.104 0 2.052.082 2.329.119v2.7h-1.598c-1.254 0-1.496.597-1.496 1.47v1.928h2.989l-.39 3.018h-2.6V20h5.098c.608 0 1.102-.494 1.102-1.104V1.104C20 .494 19.506 0 18.896 0z" />
        </svg>
    </body>
</html>

b) Use a script to transform those img tags into svg tags

✔️ You would not have to change your code + reusability
❌ Not very efficient and performant, since the client uses the JavaScript Fetch API here to request the original SVG file after the webpage has already been delivered

Mark all the img tags that display SVGs with the class svg-img and use JavaScript to turn them into svg tags, which can be styled by your (Tailwind) CSS.

Hint: When testing this locally, you should install the VSCode "Live Server" extension, and click in the bottom bar on the "Go Live" symbol to serve the files in the working directory on a local development server. Or else the fetch() will cause a CORS error: Access to fetch at 'file:///.../icon-facebook.svg' from origin 'null' has been blocked by CORS policy: ....

index.html file:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script src="https://cdn.tailwindcss.com"></script>
        <script src="transform-svg-imgs.js"></script>
    </head>
    <body class="bg-slate-900">
        <img src="icon-facebook.svg" alt="facebook logo" class="w-7 h-7 fill-white hover:fill-red-400 img-svg">
        <!-- the `transform-svg-imgs.js` script will transform above `img` element in below `svg` element
            <svg class="w-7 h-7 fill-white hover:fill-red-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" alt="facebook logo">
            <path
                d="M18.896 0H1.104C.494 0 0 .494 0 1.104v17.793C0 19.506.494 20 1.104 20h9.58v-7.745H8.076V9.237h2.606V7.01c0-2.583 1.578-3.99 3.883-3.99 1.104 0 2.052.082 2.329.119v2.7h-1.598c-1.254 0-1.496.597-1.496 1.47v1.928h2.989l-.39 3.018h-2.6V20h5.098c.608 0 1.102-.494 1.102-1.104V1.104C20 .494 19.506 0 18.896 0z" />
        </svg> -->
    </body>
</html>

transform-svg-imgs.js file:

window.onload = () => {
    // Find all <img> elements with the class "img-svg"
    const imgSVGs = document.querySelectorAll("img.img-svg");

    // Loop through each <img> element
    imgSVGs.forEach((img) => {

        // Fetch the SVG file
        fetch(img.getAttribute("src"))
            .then(response => response.text())
            .then(svgContent => {
                // Parse the XML data from the SVG file into a DOM object for easier evaluation
                const parser = new DOMParser();
                const svgXML = parser.parseFromString(svgContent, 'text/xml');

                // Create a new <svg> element
                const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");

                // Copy attributes from <img> to <svg> and remove the "img-svg" marker
                svg.setAttribute("class", img.getAttribute("class"));
                svg.classList.remove("img-svg");
                svg.setAttribute("alt", img.getAttribute("alt"));

                // Copy data from SVG file to <svg> element
                svg.setAttribute("viewBox", svgXML.getElementsByTagName("svg")[0].getAttribute("viewBox"));
                const path = svgXML.getElementsByTagName("svg")[0].querySelector("path");
                svg.appendChild(path);

                // Replace <img> with <svg>
                img.replaceWith(svg);
            })
            .catch(error => { console.log("Error fetching SVG: ", error); });

    });
};

icon-facebook.svg file:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
    <path d="M18.896 0H1.104C.494 0 0 .494 0 1.104v17.793C0 19.506.494 20 1.104 20h9.58v-7.745H8.076V9.237h2.606V7.01c0-2.583 1.578-3.99 3.883-3.99 1.104 0 2.052.082 2.329.119v2.7h-1.598c-1.254 0-1.496.597-1.496 1.47v1.928h2.989l-.39 3.018h-2.6V20h5.098c.608 0 1.102-.494 1.102-1.104V1.104C20 .494 19.506 0 18.896 0z"/>
</svg>

c) Use a workaround, like

lchristmann
  • 103
  • 1
  • 5
-1

I wanted to change specific paths and/or colors only and even colorize paths differently. Also, in my case some CSS was applied to the IMG-tag directly, hence I wanted to let it be original IMG-element to not mess around with positioning and alignment.

Thanks to inspiration from this answer: https://stackoverflow.com/a/43015413/1444589, this is what worked for me:

let img = document.querySelector('img[class^="YourClassName"]');
let imgURL = img.src;

fetch(imgURL)
  .then(response => response.text())
  .then(text => {
    let parser = new DOMParser();
    let xmlDoc = parser.parseFromString(text, 'text/xml');
    let svg = xmlDoc.getElementsByTagName('svg')[0];
    let paths = xmlDoc.getElementsByTagName('path');

    // access individual path elements directly
    let leftShape = paths[0];
    leftShape.setAttribute('fill', '#4F4F4F');

    // or find specific color
    const pathsArr = Array.from(paths);
    let skirtShape = pathsArr.find(path => path.getAttribute('fill') === '#F038A5');
    skirtShape.setAttribute('fill', '#0078D6');

    // Replace old SVG with colorized SVG
    // positioning and alignment is left untouched
    let base64Str = btoa(new XMLSerializer().serializeToString(svg));
    img.src = 'data:image/svg+xml;base64, ' + base64Str;
  });

Hans
  • 1,162
  • 11
  • 18
-2

Why not just using CSS's filter property to manipulate the color on :hover or whatever other state? I found it works over SVG images into img tags. At least, it's almost fully supported in 2020. It seams to me the simpliest solution. The only caveat is having to tweak the filter properties in order to find the target color. But you have also this very useful tool.

-2

for that matters you have to use your SVG as an inline HTML.

say here's your logo.svg code (when you open it on textEditor):

Logo.SVG

<svg width="139" height="100" xmlns="http://www.w3.org/2000/svg">
    <!-- Note that I've Added Class Attribute 'logo-img' Here -->
    <g transform="translate(-22 -45)" fill="none" fill-rule="evenodd">
        <path
            d="M158.023 48.118a7.625 7.625 0 01-.266 10.78l-88.11 83.875a7.625 7.625 0 01-10.995-.5l-33.89-38.712a7.625 7.625 0 0111.475-10.045l28.653 32.73 82.353-78.394a7.625 7.625 0 0110.78.266z"
            fill="#00000" />
    </g>
</svg>

add your desired Class/ID to it (i've added 'logo-img'):

Edited Svg

<svg class="logo-img" width="139" height="100" xmlns="http://www.w3.org/2000/svg">
    <!-- Note that I've Added Class Attribute 'logo-img' Here -->
    ...
</svg>

Now apply Your Css Rules:

CSS

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

Pro

  • With this way you can animate on user's actions (hover, selected,...)

Con

  • Your HTML File would be a mess.

Heres a Stack Snippet

<style>
        body {
            display: flex;
            justify-content: center;
        }
        .logo-img path {
            transition: .5s all linear;
        }
        .logo-img path {
            fill: coral;
        }
        .logo-img:hover path{
            fill: darkblue;
        }
        
    </style>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
</head>

<body>
    <svg class="logo-img" width="139" height="100" xmlns="http://www.w3.org/2000/svg">
        <!-- Note that I've Added Class Attribute 'logo-img' Here -->
        <g transform="translate(-22 -45)" fill="none" fill-rule="evenodd">
            <path
                d="M158.023 48.118a7.625 7.625 0 01-.266 10.78l-88.11 83.875a7.625 7.625 0 01-10.995-.5l-33.89-38.712a7.625 7.625 0 0111.475-10.045l28.653 32.73 82.353-78.394a7.625 7.625 0 0110.78.266z"
                fill="#00000" />
        </g>
    </svg>
</body>

</html>
Re9iNee
  • 412
  • 5
  • 15
-2

If your shape(s) are always one solid color and you have more than a couple, you can use Fontello and make a custom icon font with a whole series of your own custom SVG shapes. Then you can set/animate the size and color of all of them with CSS alone.

For all the possible use cases for this question, this is an essential paradigm to consider. I've used it in many projects. In any case, if you haven't heard of Fontello, you need to find out about it. If you know of a similar solution that is better, I would love to know.

Possible downfalls:

  1. Icon/shape fonts are known to mess with screen readers, so that may take some handling.

  2. Fontello can be finicky with importing shapes, and it may take some trial and error with authoring and exporting them. Avoid any and all grouping, and use only single non-nested compound shapes.

BBaysinger
  • 6,614
  • 13
  • 63
  • 132
-3

Directly to svg fill css will not work you can use as below

<style>
svg path {
    fill: red;
}
</style>
<svg xmlns="http://www.w3.org/2000/svg" width="20.666" height="59.084" viewBox="0 0 20.666 59.084"><g transform="translate(-639.749 -3139)"><path d="M648.536,3173.876c0-2.875-1.725-3.8-3.471-3.8-1.683,0-3.49.9-3.49,3.8,0,3,1.786,3.8,3.49,3.8C646.811,3177.676,648.536,3176.769,648.536,3173.876Zm-3.471,2.341c-.883,0-1.437-.513-1.437-2.341,0-1.971.615-2.381,1.437-2.381.862,0,1.438.349,1.438,2.381,0,1.907-.616,2.339-1.438,2.339Z" fill="#142312"/><path d="M653.471,3170.076a1.565,1.565,0,0,0-1.416.9l-6.558,13.888h1.2a1.565,1.565,0,0,0,1.416-.9l6.559-13.887Z" fill="#142312"/><path d="M655.107,3177.263c-1.684,0-3.471.9-3.471,3.8,0,3,1.766,3.8,3.471,3.8,1.745,0,3.49-.9,3.49-3.8C658.6,3178.186,656.851,3177.263,655.107,3177.263Zm0,6.139c-.884,0-1.438-.514-1.438-2.34,0-1.972.617-2.381,1.438-2.381.862,0,1.437.349,1.437,2.381,0,1.909-.616,2.34-1.437,2.34Z" fill="#142312"/><path d="M656.263,3159.023l-1.49-14.063a1.35,1.35,0,0,0,.329-.293,1.319,1.319,0,0,0,.268-1.123l-.753-3.49a1.328,1.328,0,0,0-1.306-1.054h-6.448a1.336,1.336,0,0,0-1.311,1.068l-.71,3.493a1.344,1.344,0,0,0,.276,1.112,1.532,1.532,0,0,0,.283.262l-1.489,14.087c-1.7,1.727-4.153,4.871-4.153,8.638v28.924a1.339,1.339,0,0,0,1.168,1.49,1.357,1.357,0,0,0,.17.01h17.981a1.366,1.366,0,0,0,1.337-1.366v-29.059C660.414,3163.893,657.963,3160.749,656.263,3159.023Zm-8.307-17.349h4.274l.176.815H647.79Zm9.785,43.634v10.1H642.434v-17.253a4.728,4.728,0,0,1-2.028-4.284,4.661,4.661,0,0,1,2.028-4.215v-2c0-3.162,2.581-5.986,3.687-7.059a1.356,1.356,0,0,0,.4-.819l1.542-14.614H652.1l1.545,14.618a1.362,1.362,0,0,0,.4.819c1.109,1.072,3.688,3.9,3.688,7.059v9.153a5.457,5.457,0,0,1,0,8.5Z" fill="#142312"/></g></svg>

This worked for me

Jayant Patil
  • 1,537
  • 2
  • 11
  • 18