How to change color of SVG image using CSS (jQuery SVG image replacement)?
Asked Answered
C

19

470

This is a self Q&A of a handy piece of code I came up with.

Currently, there isn't an easy way to embed an SVG image and then have access to the SVG elements via CSS. There are various methods of using JS SVG frameworks, but they are overly complicated if all you are doing is making a simple icon with a rollover state.

So here is what I came up with, which I think is by far the easiest way to use SVG files on a website. It takes its concept from the early text-to-image replacement methods, but as far as I am aware has never been done for SVGs.

This is the question:

How do I embed an SVG and change its color in CSS without using a JS-SVG framework?

Cyclo answered 16/8, 2012 at 0:5 Comment(2)
Unfortunately the img tag doesn't work with svg files in IE, so keep in mind that. IE recognize embed tags. Anyway, nice job!Venatic
For svg, you should use the "fill" css property. For images it's appropriate to use "filter". "Filter" does in fact work for both but it is unnecessary to do all of that work for a vector graphic.Layoff
C
561

Firstly, use an IMG tag in your HTML to embed an SVG graphic. I used Adobe Illustrator to make the graphic.

<img id="facebook-logo" class="svg social-link" src="/images/logo-facebook.svg"/>

This is just like how you'd embed a normal image. Note that you need to set the IMG to have a class of svg. The 'social-link' class is just for examples sake. The ID is not required, but is useful.

Then use this jQuery code (in a separate file or inline in the HEAD).

    /**
     * Replace all SVG images with inline SVG
     */
        jQuery('img.svg').each(function(){
            var $img = jQuery(this);
            var imgID = $img.attr('id');
            var imgClass = $img.attr('class');
            var imgURL = $img.attr('src');

            jQuery.get(imgURL, function(data) {
                // Get the SVG tag, ignore the rest
                var $svg = jQuery(data).find('svg');

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

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

                // Replace image with new SVG
                $img.replaceWith($svg);

            }, 'xml');

        });

What the above code does is look for all IMG's with the class 'svg' and replace it with the inline SVG from the linked file. The massive advantage is that it allows you to use CSS to change the color of the SVG now, like so:

svg:hover path {
    fill: red;
}

The jQuery code I wrote also ports across the original images ID and classes. So this CSS works too:

#facebook-logo:hover path {
    fill: red;
}

Or:

.social-link:hover path {
    fill: red;
}

You can see an example of it working here: http://labs.funkhausdesign.com/examples/img-svg/img-to-svg.html

We have a more complicated version that includes caching here: https://github.com/funkhaus/style-guide/blob/master/template/js/site.js#L32-L90

Cyclo answered 16/8, 2012 at 0:5 Comment(6)
This is awesome! I've been looking for a way to keep the markup clean, but still allow access to the svg "innards" for use in CSS. This should work, but I'm getting an error with the JS: "XMLHttpRequest cannot load file:///H:/svg/test/test.svg. Origin null is not allowed by Access-Control-Allow-Origin." Any ideas?Rumen
My guess is because you are running it locally and getting a cross domain problem. Put it on a server and it should work.Cyclo
If you put this in the onDocumentReady handler, you may get the FOUC (flash of unstyled content) effect where it renders the original <img> tags before replacing them with the <svg>. If there were some way to run this immediately before each <img> tag is rendered, it would be perfect. I suppose you could also use CSS to hide 'img.svg' elements so they only render after the replacement occurs.Idonah
It may sometimes not work in Safari (for e.g.), to ensure returned data is readable, remplace the }); of $.get with }, 'xml');Informal
You could probably even replace the selector with img[src$=".svg"] and eliminate the need for the svg class.Magnanimous
It works but I can't manipulate attributes of replaced image from my JS anymore, regardless whether this script was loaded before or after mine. Replaced element is successfully bound in my script, it just doesn't work without any clues. I don't understand why. If I manually insert produced HTML, it works as expected.Shick
M
60

Style

svg path {
    fill: #000;
}

Script

$(document).ready(function() {
    $('img[src$=".svg"]').each(function() {
        var $img = jQuery(this);
        var imgURL = $img.attr('src');
        var attributes = $img.prop("attributes");

        $.get(imgURL, function(data) {
            // Get the SVG tag, ignore the rest
            var $svg = jQuery(data).find('svg');

            // Remove any invalid XML tags
            $svg = $svg.removeAttr('xmlns:a');

            // Loop through IMG attributes and apply on SVG
            $.each(attributes, function() {
                $svg.attr(this.name, this.value);
            });

            // Replace IMG with SVG
            $img.replaceWith($svg);
        }, 'xml');
    });
});
Mercedezmerceer answered 1/2, 2016 at 9:21 Comment(4)
If you don't have a width attr, it just creates one with a wrong number. width="170.667" in my caseBaillargeon
This isnt perfect since it loses the previous img dimensions.Kaylyn
Hello suppose i have different svg with differnet color each. Using this method, all my svg colors become the same as the first svg that is being looped. Any idea how can I maneuver around this so each color stays the same as before?Calicle
note that if your svg is made also from non-path shapes (like rect) you'd need to handle them in css as wellPolemic
G
43

You can now use the CSS filter property in most modern browsers (including Edge, but not IE11). It works on SVG images as well as other elements. You can use hue-rotate or invert to modify colors, although they don't let you modify different colors independently. I use the following CSS class to show a "disabled" version of an icon (where the original is an SVG picture with saturated color):

.disabled {
    opacity: 0.4;
    filter: grayscale(100%);
    -webkit-filter: grayscale(100%);
}

This makes it light grey in most browsers. In IE (and probably Opera Mini, which I haven't tested) it is noticeably faded by the opacity property, which still looks pretty good, although it's not grey.

Here's an example with four different CSS classes for the Twemoji bell icon: original (yellow), the above "disabled" class, hue-rotate (green), and invert (blue).

.twa-bell {
  background-image: url("https://twemoji.maxcdn.com/svg/1f514.svg");
  display: inline-block;
  background-repeat: no-repeat;
  background-position: center center;
  height: 3em;
  width: 3em;
  margin: 0 0.15em 0 0.3em;
  vertical-align: -0.3em;
  background-size: 3em 3em;
}
.grey-out {
  opacity: 0.4;
  filter: grayscale(100%);
  -webkit-filter: grayscale(100%);
}
.hue-rotate {
  filter: hue-rotate(90deg);
  -webkit-filter: hue-rotate(90deg);
}
.invert {
  filter: invert(100%);
  -webkit-filter: invert(100%);
}
<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <span class="twa-bell"></span>
  <span class="twa-bell grey-out"></span>
  <span class="twa-bell hue-rotate"></span>
  <span class="twa-bell invert"></span>
</body>

</html>
Gunter answered 28/6, 2016 at 19:10 Comment(3)
Just noticed that invert is good solution if you don't want to create icon fonts. I used this jQuery code to change icon in my website's header according to css color property (notice that I am using white png icons): if ($('.w3-top img').css("color") == "rgb(0, 0, 0)") { $('.w3-top img').css("filter", "invert(100%)"); $('.w3-top img').css("-webkit-filter", "invert(100%)"); };Beggarweed
Great approach. Edited my SVG xml to add the target icon color then used an .icon-disabled class to gray it out.Revise
Notice that old Explores doesn't support filter: w3schools.com/cssref/css3_pr_filter.aspOrnament
I
26

Alternatively you could use CSS mask, granted browser support isn't good but you could use a fallback

.frame {
    background: blue;
    -webkit-mask: url(image.svg) center / contain no-repeat;
}
Interlace answered 14/8, 2014 at 10:22 Comment(3)
MDN specifies that -webkit-mask should not be used on any production website.Melissamelisse
doesn't color the svgUlulant
Maybe it's relevant to say that now, four years later, this solution is working in all major browsers. Just tested here and it's 100% ok.Sustainer
B
24

If you can include files (PHP include or include via your CMS of choice) in your page, you can add the SVG code and include it into your page. This works the same as pasting the SVG source into the page, but makes the page markup cleaner.

The benefit is that you can target parts of your SVG via CSS for hover -- no javascript required.

http://codepen.io/chriscoyier/pen/evcBu

You just have to use a CSS rule like this:

#pathidorclass:hover { fill: #303 !important; }

Note that the !important bit is necessary to override the fill color.

Bravado answered 1/10, 2013 at 16:1 Comment(3)
For those using AngularJS: <div ng-include="'svg.svg'"></div>Lefebvre
Not a very elegant solution storing svg data in a database though. Not wrong, but pumping out xml/html/svg DOM data from an API or CMS rather than using templates or other assets just feels wrong.Panelboard
Additionally, if your SVG has transparent areas, these won't count as hovering and you may experience "flashy hover". To fix that, just add a wrapper element (an <a>, if it's convenient) and then add that to the CSS rule. #pathidorclass:hover, .wrapperclass:hover #pathidorclass { fill: green; } Or even just eliminate the original hover of the SVG path since you are targeting it via the wrapper element now anyway.Deferment
I
24

TL/DR: GO here-> https://codepen.io/sosuke/pen/Pjoqqp

Explanation:

I'm assuming you have html something like this:

<img src="/img/source.svg" class="myClass">

Definitely go the filter route, ie. your svg is most likely black or white. You can apply a filter to get it to be whatever color you want, for example, I have a black svg that I want mint green. I first invert it to be white (which is technically all RGB colors on full) then play with the hue saturation etc. To get it right:

filter: invert(86%) sepia(21%) saturate(761%) hue-rotate(92deg) brightness(99%) contrast(107%);

Even better is that you could just use a tool to convert the hex you want into a filter for you: https://codepen.io/sosuke/pen/Pjoqqp

Idomeneus answered 19/2, 2020 at 19:27 Comment(0)
G
19

@Drew Baker gave a great solution to solve the problem. The code works properly. However, those who uses AngularJs may find lots of dependency on jQuery. Consequently, I thought it is a good idea to paste for AngularJS users, a code following @Drew Baker's solution.

AngularJs way of the same code

1. Html: use the bellow tag in you html file:

<svg-image src="/icons/my.svg" class="any-class-you-wish"></svg-image>

2. Directive: this will be the directive that you will need to recognise the tag:

'use strict';
angular.module('myApp')
  .directive('svgImage', ['$http', function($http) {
    return {
      restrict: 'E',
      link: function(scope, element) {
        var imgURL = element.attr('src');
        // if you want to use ng-include, then
        // instead of the above line write the bellow:
        // var imgURL = element.attr('ng-include');
        var request = $http.get(
          imgURL,
          {'Content-Type': 'application/xml'}
        );

        scope.manipulateImgNode = function(data, elem){
          var $svg = angular.element(data)[4];
          var imgClass = elem.attr('class');
          if(typeof(imgClass) !== 'undefined') {
            var classes = imgClass.split(' ');
            for(var i = 0; i < classes.length; ++i){
              $svg.classList.add(classes[i]);
            }
          }
          $svg.removeAttribute('xmlns:a');
          return $svg;
        };

        request.success(function(data){
          element.replaceWith(scope.manipulateImgNode(data, element));
        });
      }
    };
  }]);

3. CSS:

.any-class-you-wish{
    border: 1px solid red;
    height: 300px;
    width:  120px
}

4. Unit-test with karma-jasmine:

'use strict';

describe('Directive: svgImage', function() {

  var $rootScope, $compile, element, scope, $httpBackend, apiUrl, data;

  beforeEach(function() {
    module('myApp');

    inject(function($injector) {
      $rootScope = $injector.get('$rootScope');
      $compile = $injector.get('$compile');
      $httpBackend = $injector.get('$httpBackend');
      apiUrl = $injector.get('apiUrl');
    });

    scope = $rootScope.$new();
    element = angular.element('<svg-image src="/icons/icon-man.svg" class="svg"></svg-image>');
    element = $compile(element)(scope);

    spyOn(scope, 'manipulateImgNode').andCallThrough();
    $httpBackend.whenGET(apiUrl + 'me').respond(200, {});

    data = '<?xml version="1.0" encoding="utf-8"?>' +
      '<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->' +
      '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' +
      '<!-- Obj -->' +
      '<!-- Obj -->' +
      '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"' +
      'width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">' +
        '<g>' +
          '<path fill="#F4A902" d=""/>' +
          '<path fill="#F4A902" d=""/>' +
        '</g>' +
      '</svg>';
    $httpBackend.expectGET('/icons/icon-man.svg').respond(200, data);
  });

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  it('should call manipulateImgNode atleast once', function () {
    $httpBackend.flush();
    expect(scope.manipulateImgNode.callCount).toBe(1);
  });

  it('should return correct result', function () {
    $httpBackend.flush();
    var result = scope.manipulateImgNode(data, element);
    expect(result).toBeDefined();
  });

  it('should define classes', function () {
    $httpBackend.flush();
    var result = scope.manipulateImgNode(data, element);
    var classList = ["svg"];
    expect(result.classList[0]).toBe(classList[0]);
  });
});
Gnarl answered 27/1, 2015 at 9:34 Comment(7)
your solution does not work, could be <div ng-include="/icons/my.svg" class="any-class-you-wish"></div>Strep
@guillaumevincent if you want to use it with ng-include then just change this line var imgURL = element.attr('src'); to var imgURL = element.attr('ng-include');Gnarl
This is a very handy solution, but be careful in overusing it as it can hit performance pretty hard - I.E. a set of 5 sharing icons repeated on an article listing or something like that.Millet
There is a problem with your code in IE. You can use just if (typeof(imgClass) !== 'undefined') { $svg.setAttribute("class", imgClass); } instead of split and for loop.Repression
i want to load svg from amazon s3, but unfortunately not working inside ng-repeat, giving TypeError: Cannot read property 'protocol' of undefinedCompany
@guillaumevincent awesome, no need for any directive, ng-include straight up does all that, perfect!Zimbabwe
Awesome work! But for certain image you need to grab the first element of the svg (angular.element(data)[0];) and to make it work with IE use if ($svg.getAttribute('class')) { $svg.setAttribute('class', $svg.getAttribute('class') + ' ' + imgClass); } else { $svg.setAttribute('class', imgClass); }. Also you might want to add cache: true to the options of $http.get otherwise your page might become very slow.Balaam
T
19

I realize you're wanting to accomplish this with CSS, but just a reminder in case it's a small, simple image - you can always pop it open in Notepad++ and change the path/whateverelement's fill:

<path style="fill:#010002;" d="M394.854,205.444c9.218-15.461,19.102-30.181,14.258-49.527
    ...
    C412.843,226.163,402.511,211.451,394.854,205.444z"/>

It could save a ton of ugly script. Sorry if it's off-base, but sometimes the simple solutions can be overlooked.

...even swapping multiple svg images might be smaller in size than some of the code snippets for this question.

Tula answered 3/1, 2018 at 22:23 Comment(0)
I
8

I wrote a directive to solve this issue with AngularJS. It is available here - ngReusableSvg.

It replaces the SVG element after it's been rendered, and places it inside a div element, making its CSS easily changeable. This helps using the same SVG file in different places using different sizes/colors.

The usage is simple:

<object oa-reusable-svg
        data="my_icon.svg"
        type="image/svg+xml"
        class="svg-class"
        height="30"  // given to prevent UI glitches at switch time
        width="30">
</object>

After that, you can easily have:

.svg-class svg {
    fill: red; // whichever color you want
}
Internship answered 16/9, 2015 at 20:21 Comment(2)
Hi, thanks for providing this solution. I've tried it and it yields: <div ng-click="eventHandler()" ng-class="classEventHandler()" style="height:30px; width:30px;float:left;" class="svg-class" id="my-svg" height="30" width="30">[[object SVGSVGElement]]</div> In the html it then just puts [[object SVGSVGElement]]. Do you know what's the problem? Another question, does it have a large impact on performance or can I use it on many svg's on a page? And lastly, it's still on angular 1.3 (the bower).Picco
Which version of angular are you using? Haven't encountered your issue.. maybe it's something with the SVG? Performance-wise the switch is relatively heavy, I've used it myself on like 10 and it was fine.. I guess that depends on amount/size, so trial and experiment with it. What's the problem with the bower? Are you using a different version and there's a conflict?Internship
D
6

Here's a version for knockout.js based on the accepted answer:

Important: It does actually require jQuery too for the replacing, but I thought it may be useful to some.

ko.bindingHandlers.svgConvert =
    {
        'init': function ()
        {
            return { 'controlsDescendantBindings': true };
        },

        'update': function (element, valueAccessor, allBindings, viewModel, bindingContext)
        {
            var $img = $(element);
            var imgID = $img.attr('id');
            var imgClass = $img.attr('class');
            var imgURL = $img.attr('src');

            $.get(imgURL, function (data)
            {
                // Get the SVG tag, ignore the rest
                var $svg = $(data).find('svg');

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

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

                // Replace image with new SVG
                $img.replaceWith($svg);

            }, 'xml');

        }
    };

Then just apply data-bind="svgConvert: true" to your img tag.

This solution completely replaces the img tag with a SVG and any additional bindings would not be respected.

Despairing answered 1/10, 2016 at 2:53 Comment(3)
This is great! If you want to take it to the next level, we have an updated version that includes caching, so the same SVG isn't requested twice. github.com/funkhaus/style-guide/blob/master/template/js/…Cyclo
I was a bit worried about that but didn't have time to look into it myself. Just needed something quickDespairing
@DrewBaker actually I was more concerned that the img tag would request the file and then the get would request it again. I considered changing the src to a data-src attribute on the img tag, but concluded that modern browsers are probably smart enough to cache the file anywayDespairing
C
6

There is an open source library called SVGInject that uses the onload attribute to trigger the injection. You can find the GitHub project at https://github.com/iconfu/svg-inject

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

Coruscate answered 4/9, 2018 at 16:4 Comment(0)
G
4

Here's a no framework code, only pure js :

document.querySelectorAll('img.svg').forEach(function(element) {
            var imgID = element.getAttribute('id')
            var imgClass = element.getAttribute('class')
            var imgURL = element.getAttribute('src')

            xhr = new XMLHttpRequest()
            xhr.onreadystatechange = function() {
                if(xhr.readyState == 4 && xhr.status == 200) {
                    var svg = xhr.responseXML.getElementsByTagName('svg')[0];

                    if(imgID != null) {
                         svg.setAttribute('id', imgID);
                    }

                    if(imgClass != null) {
                         svg.setAttribute('class', imgClass + ' replaced-svg');
                    }

                    svg.removeAttribute('xmlns:a')

                    if(!svg.hasAttribute('viewBox') && svg.hasAttribute('height') && svg.hasAttribute('width')) {
                        svg.setAttribute('viewBox', '0 0 ' + svg.getAttribute('height') + ' ' + svg.getAttribute('width'))
                    }
                    element.parentElement.replaceChild(svg, element)
                }
            }
            xhr.open('GET', imgURL, true)
            xhr.send(null)
        })
Gundry answered 7/11, 2017 at 20:41 Comment(0)
M
3

If we have a greater number of such svg images we can also take the help of font-files.
Sites like https://glyphter.com/ can get us a font file from our svgs.


E.g.

@font-face {
    font-family: 'iconFont';
    src: url('iconFont.eot');
}
#target{
    color: white;
    font-size:96px;
    font-family:iconFont;
}
Mopes answered 7/7, 2015 at 19:25 Comment(3)
I personally hate the "images as a font" technique. It makes it hard to add/edit images, adds a lot of nonsensical markup. Font's should be fonts, images should be images etc.Cyclo
Agreed. You also need to remember/lookup the images assigned to characters. but for the specific case where images are used as icons/button/bullets, act more as text than media, font-files can also be an alternativeMopes
even github don't use font anymore for icon github.com/blog/2112-delivering-octicons-with-svgMagdamagdaia
O
3

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:

  1. Mozilla Firefox 59.0.2 (64-bit) Linux

enter image description here

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

enter image description here

  1. Opera 53.0.2907.37 Linux

enter image description here

Oaken answered 6/6, 2018 at 20:17 Comment(0)
S
2

You can use data-image for that. using data-image(data-URI) you can access SVG like inline.

Here is rollover effect using pure CSS and SVG.

I know it messy but you can do this way.

 .action-btn {
    background-size: 20px 20px;
    background-position: center center;
    background-repeat: no-repeat;
    border-width: 1px;
    border-style: solid;
    border-radius: 30px;
    height: 40px;
    width: 60px;
    display: inline-block;
 }

.delete {
     background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg version='1.1' id='Capa_1' fill='#FB404B' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='482.428px' height='482.429px' viewBox='0 0 482.428 482.429' style='enable-background:new 0 0 482.428 482.429;' xml:space='preserve'%3e%3cg%3e%3cg%3e%3cpath d='M381.163,57.799h-75.094C302.323,25.316,274.686,0,241.214,0c-33.471,0-61.104,25.315-64.85,57.799h-75.098 c-30.39,0-55.111,24.728-55.111,55.117v2.828c0,23.223,14.46,43.1,34.83,51.199v260.369c0,30.39,24.724,55.117,55.112,55.117 h210.236c30.389,0,55.111-24.729,55.111-55.117V166.944c20.369-8.1,34.83-27.977,34.83-51.199v-2.828 C436.274,82.527,411.551,57.799,381.163,57.799z M241.214,26.139c19.037,0,34.927,13.645,38.443,31.66h-76.879 C206.293,39.783,222.184,26.139,241.214,26.139z M375.305,427.312c0,15.978-13,28.979-28.973,28.979H136.096 c-15.973,0-28.973-13.002-28.973-28.979V170.861h268.182V427.312z M410.135,115.744c0,15.978-13,28.979-28.973,28.979H101.266 c-15.973,0-28.973-13.001-28.973-28.979v-2.828c0-15.978,13-28.979,28.973-28.979h279.897c15.973,0,28.973,13.001,28.973,28.979 V115.744z'/%3e%3cpath d='M171.144,422.863c7.218,0,13.069-5.853,13.069-13.068V262.641c0-7.216-5.852-13.07-13.069-13.07 c-7.217,0-13.069,5.854-13.069,13.07v147.154C158.074,417.012,163.926,422.863,171.144,422.863z'/%3e%3cpath d='M241.214,422.863c7.218,0,13.07-5.853,13.07-13.068V262.641c0-7.216-5.854-13.07-13.07-13.07 c-7.217,0-13.069,5.854-13.069,13.07v147.154C228.145,417.012,233.996,422.863,241.214,422.863z'/%3e%3cpath d='M311.284,422.863c7.217,0,13.068-5.853,13.068-13.068V262.641c0-7.216-5.852-13.07-13.068-13.07 c-7.219,0-13.07,5.854-13.07,13.07v147.154C298.213,417.012,304.067,422.863,311.284,422.863z'/%3e%3c/g%3e%3c/g%3e%3c/svg%3e ");
     border-color:#FB404B;
     
 }
 
 .delete:hover {
     background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg version='1.1' id='Capa_1' fill='#fff' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='482.428px' height='482.429px' viewBox='0 0 482.428 482.429' style='enable-background:new 0 0 482.428 482.429;' xml:space='preserve'%3e%3cg%3e%3cg%3e%3cpath d='M381.163,57.799h-75.094C302.323,25.316,274.686,0,241.214,0c-33.471,0-61.104,25.315-64.85,57.799h-75.098 c-30.39,0-55.111,24.728-55.111,55.117v2.828c0,23.223,14.46,43.1,34.83,51.199v260.369c0,30.39,24.724,55.117,55.112,55.117 h210.236c30.389,0,55.111-24.729,55.111-55.117V166.944c20.369-8.1,34.83-27.977,34.83-51.199v-2.828 C436.274,82.527,411.551,57.799,381.163,57.799z M241.214,26.139c19.037,0,34.927,13.645,38.443,31.66h-76.879 C206.293,39.783,222.184,26.139,241.214,26.139z M375.305,427.312c0,15.978-13,28.979-28.973,28.979H136.096 c-15.973,0-28.973-13.002-28.973-28.979V170.861h268.182V427.312z M410.135,115.744c0,15.978-13,28.979-28.973,28.979H101.266 c-15.973,0-28.973-13.001-28.973-28.979v-2.828c0-15.978,13-28.979,28.973-28.979h279.897c15.973,0,28.973,13.001,28.973,28.979 V115.744z'/%3e%3cpath d='M171.144,422.863c7.218,0,13.069-5.853,13.069-13.068V262.641c0-7.216-5.852-13.07-13.069-13.07 c-7.217,0-13.069,5.854-13.069,13.07v147.154C158.074,417.012,163.926,422.863,171.144,422.863z'/%3e%3cpath d='M241.214,422.863c7.218,0,13.07-5.853,13.07-13.068V262.641c0-7.216-5.854-13.07-13.07-13.07 c-7.217,0-13.069,5.854-13.069,13.07v147.154C228.145,417.012,233.996,422.863,241.214,422.863z'/%3e%3cpath d='M311.284,422.863c7.217,0,13.068-5.853,13.068-13.068V262.641c0-7.216-5.852-13.07-13.068-13.07 c-7.219,0-13.07,5.854-13.07,13.07v147.154C298.213,417.012,304.067,422.863,311.284,422.863z'/%3e%3c/g%3e%3c/g%3e%3c/svg%3e ");        
     background-color: #FB404B;
    }
<a class="action-btn delete">&nbsp;</a>

You can convert your svg to data url here

  1. https://codepen.io/elliz/full/ygvgay
  2. https://websemantics.uk/tools/svg-to-background-image-conversion/
Selfannihilation answered 7/5, 2018 at 11:45 Comment(4)
This wouldn't work for complex SVGs where you only want certain paths/polygons/etc.. to change on hover right?Cyclo
No you can..but it very complexSelfannihilation
It just solutions for iconSelfannihilation
If some work with icon. Then it great. Bootstrap 4 also use this technicSelfannihilation
U
1

The selected solution is fine if you want jQuery to process all svg elements in your DOM and your DOM is of reasonable size. But if your DOM is large and you decide to load parts of your DOM dynamically, it really makes no sense to have to rescan the entire DOM just to update svg elements. Instead, use a jQuery plugin to do this:

/**
 * A jQuery plugin that loads an svg file and replaces the jQuery object with its contents.
 *
 * The path to the svg file is specified in the src attribute (which normally does not exist for an svg element).
 *
 * The width, height and class attributes in the loaded svg will be replaced by those that exist in the jQuery object's
 * underlying html. Note: All other attributes in the original element are lost including the style attribute. Place
 * any styles in a style class instead.
 */
(function ($) {
    $.fn.svgLoader = function () {
        var src = $(this).attr("src");
        var width = this.attr("width");
        var height = this.attr("height");
        var cls = this.attr("class");
        var ctx = $(this);

        // Get the svg file and replace the <svg> element.
        $.ajax({
            url: src,
            cache: false
        }).done(function (html) {
            let svg = $(html);
            svg.attr("width", width);
            svg.attr("height", height);
            svg.attr("class", cls);
            var newHtml = $('<a></a>').append(svg.clone()).html();
            ctx.replaceWith(newHtml);
        });

        return this;
    };

}(jQuery));

In your html, specify an svg element as follows:

<svg src="images/someSvgFile.svg" height="45" width="45" class="mySVGClass"/>

And apply the plugin:

$(".mySVGClass").svgLoader();
Unmeriting answered 8/6, 2017 at 6:15 Comment(1)
Yeah there are certainly more efficient ways to use the code I gave. Here is how we actually use it on production sites. It caches SVGs! github.com/funkhaus/style-guide/blob/master/template/js/…Cyclo
X
1

for :hover event animations we can left the styles inside svg file, like a

<svg xmlns="http://www.w3.org/2000/svg">
<defs>
  <style>
  rect {
    fill:rgb(165,225,75);
    stroke:none;
    transition: 550ms ease-in-out;
    transform-origin:125px 125px;
  }
  rect:hover {
    fill:rgb(75,165,225);
    transform:rotate(360deg);
  }
  </style>
</defs>
  <rect x='50' y='50' width='150' height='150'/>
</svg>

check this on svgshare

Xuthus answered 20/6, 2018 at 12:50 Comment(0)
C
0
.carousel-control-prev-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='rgb(3,122,247)' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e");
}

chnage color : fill='rgb(3,122,247)'

Cuesta answered 26/4, 2021 at 11:12 Comment(0)
U
0

Since 2015 there is an easy way to do this in plain JavaScript using the JavaScript Fetch API

"There was a time when XMLHttpRequest was used to make API requests. Using jQuery, you could use the cleaner syntax of jQuery.ajax(). Now, JavaScript has its own built-in way to make API requests." ~ Digital Ocean

  1. HTML: Use <img> tags and give a class of "svg" to all those <img> tags, which have an SVG file as a source.
<img class="svg" src="/images/logo-facebook.svg"/>
  1. JavaScript: Put this code in a separate file or inline, at the end of the <body> or in the <head>, doesn't matter.
window.onload = () => {
    // Find all <img> elements with a class of "svg"
    const imgSVGs = document.querySelectorAll("img.svg");

    // Loop over each found 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>: class, alt, id
                // Remove the helper class "svg"
                svg.setAttribute("class", img.getAttribute("class"));
                svg.classList.remove("svg");
                if (img.getAttribute("id"))
                    svg.setAttribute("id", img.getAttribute("id"));
                if (img.getAttribute("alt"))
                    svg.setAttribute("alt", img.getAttribute("alt"));

                // Copy data from SVG file to <svg>: viewBox attribute, SVG path
                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); });

    });
};

This short script transforms all <img> elements with a class of svg into real <svg> elements, which can then be styled with CSS, like so:

svg:hover {
    fill: red;
}

It copies the attributes id, alt and class over from the <img> to the <svg> (if they are present) and takes the <path> element and the viewBox attribute from the original SVG file.

✔️ Same behavior as the accepted jQuery code, but with only JavaScript, no frameworks.

Underbodice answered 23/8, 2023 at 18:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.