如何使用CSS(jQuery SVG图像replace)更改SVG图像的颜色?

这是我自己提出的一个方便的代码的自我问答。

目前,embeddedSVG图像并不容易,然后通过CSS访问SVG元素。 有很多使用JS SVG框架的方法,但是如果你正在做的只是一个带有翻转状态的简单图标,那么它们就太复杂了。

所以这就是我想到的,我认为这是在网站上使用SVG文件的最简单的方法。 它从早期的文本到图像replace方法的概念,但据我所知SVGs从来没有做过。

这是一个问题:

如何在不使用JS-SVG框架的情况下embeddedSVG并将其颜色更改为CSS?

首先,在HTML中使用IMG标签来embeddedSVGgraphics。 我使用Adobe Illustrator来制作graphics。

<img id="facebook-logo" class="svg social-link" src="http://img.dovov.comlogo-facebook.svg"/> 

这就像你如何embedded一个正常的图像。 请注意,您需要将IMG设置为具有一类svg。 “社交链接”类仅仅是为了举例。 该ID不是必需的,但是有用的。

然后使用这个jQuery代码(在一个单独的文件或在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'); }); 

上面的代码是用类“svg”查找所有IMG,并用链接文件中的内联SVGreplace它。 其巨大的优势是,它允许您现在使用CSS来更改SVG的颜色,如下所示:

 svg:hover path { fill: red; } 

我写的jQuery代码还在原始的图像ID和类中移植。 所以这个CSS也起作用:

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

要么:

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

你可以在这里看到一个例子: http : //labs.funkhausdesign.com/examples/img-svg/img-to-svg.html

我们有一个更复杂的版本,包括caching在这里: https : //github.com/funkhaus/style-guide/blob/master/template/js/site.js#L32-L90

样式

 svg path { fill: #000; } 

脚本

 $(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'); }); }); 

或者你可以使用CSS mask ,授予浏览器支持不好,但你可以使用后备

 .frame { background: blue; -webkit-mask: url(image.svg) center / contain no-repeat; } 

德鲁·贝克给了一个很好的解决scheme来解决这个问题。 代码正常工作。 但是,那些使用AngularJs的人可能会发现很多依赖于jQuery的东西。 因此,我认为粘贴AngularJS用户是一个好主意,这是一个遵循@Drew Baker解决scheme的代码。

AngularJs方式相同的代码

1. Html :在你的HTML文件中使用bellow标签:

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

2.指令 :这将是您需要识别标签的指令:

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

 '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]); }); }); 

如果您可以在页面中包含文件(包括PHP或通过您select的CMS进行包含),则可以添加SVG代码并将其包含到页面中。 这与将SVG源粘贴到页面中相同,但使页面标记更清晰。

好处是你可以通过CSShover你的SVG的部分 – 不需要JavaScript。

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

你只需要使用像这样的CSS规则:

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

请注意!important位是必要的来覆盖填充颜色。

现在,您可以在大多数现代浏览器 (包括Edge,但不包括IE11)中使用CSS filter属性 。 它适用于SVG图像以及其他元素。 您可以使用色调旋转或反转来修改颜色,尽pipe它们不允许您独立修改不同的颜色。 我使用下面的CSS类来显示图标的“禁用”版本(其中原始图像是饱和颜色的SVG图片):

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

这使得在大多数浏览器中呈灰色。 在IE浏览器(也许Opera Mini,我还没有testing过)中,它的不透明属性显然已经消失了,尽pipe它不是灰色的,但它看起来还是很不错的。

下面是Twemoji铃铛图标的四个不同CSS类的示例 :原始(黄色),上面的“禁用”类, hue-rotate (绿色)和invert (蓝色)。

 .twa-bell { background-image: url("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> 

我写了一个指令来解决与AngularJS这个问题。 它在这里可用- ngReusableSvg 。

它在渲染之后replace了SVG元素,并将其放置在div元素中,使其CSS变得很容易。 这有助于在不同的地方使用不同的大小/颜色使用相同的SVG文件。

用法很简单:

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

之后,您可以轻松拥有:

 .svg-class svg { fill: red; // whichever color you want } 

如果我们有更多这样的svg图像,我们也可以借助字体文件。
https://glyphter.com/这样的站点可以从我们的svgs中得到一个字体文件。;


例如

 @font-face { font-family: 'iconFont'; src: url('iconFont.eot'); } #target{ color: white; font-size:96px; font-family:iconFont; } 

以下是基于公认的答案的knockout.js版本:

重要的是:它实际上也需要jQueryreplace,但我认为它可能对一些有用。

 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'); } }; 

然后,将data-bind="svgConvert: true"应用于您的img标签。

这个解决scheme完全用SVGreplace了img标签,任何额外的绑定都不会被尊重。

如果您希望jQuery处理DOM中的所有svg元素,并且您的DOM具有合理的大小,选定的解决scheme就没有问题。 但是,如果你的DOM很大,而且你决定dynamic地加载你的DOM的一部分,那么为了更新svg元素,必须重新扫描整个DOM是没有意义的。 相反,使用jQuery插件来做到这一点:

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

在你的html中,指定一个svg元素如下:

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

并应用插件:

 $(".mySVGClass").svgLoader(); 

这是一个没有框架的代码,只有纯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 == 0 || 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) })