How to change color of SVG image using CSS (jQuery SVG image replacement)?
这是我提出的一个方便的代码的自我问答。
目前,没有一种简单的方法来嵌入SVG图像,然后通过CSS访问SVG元素。 有各种使用JS SVG框架的方法,但如果你所做的只是制作一个带有翻转状态的简单图标,它们就会过于复杂。
所以这就是我提出的,我认为这是迄今为止在网站上使用SVG文件的最简单方法。 它从早期的文本到图像替换方法中采用了它的概念,但据我所知,SVG从未做过。
这是个问题:
如何在不使用JS-SVG框架的情况下嵌入SVG并在CSS中更改其颜色?
首先,在HTML中使用IMG标记嵌入SVG图形。我使用Adobe Illustrator制作图形。
1 | <img id="facebook-logo" class="svg social-link" src="/images/logo-facebook.svg"/> |
这就像你嵌入正常图像一样。请注意,您需要将IMG设置为具有svg类。"社交链接"类只是为了举例。该ID不是必需的,但很有用。
然后使用这个jQuery代码(在单独的文件中或在HEAD中内联)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /* * 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,并将其替换为链接文件中的内联SVG。它的巨大优势在于它允许您现在使用CSS来更改SVG的颜色,如下所示:
1 2 3 | svg:hover path { fill: red; } |
我写的jQuery代码也跨越原始图像ID和类。所以这个CSS也适用:
1 2 3 | #facebook-logo:hover path { fill: red; } |
要么:
1 2 3 | .social-link:hover path { fill: red; } |
你可以在这里看到它的一个例子:
http://labs.funkhausdesign.com/examples/img-svg/img-to-svg.html
我们有一个更复杂的版本,包括缓存:
https://github.com/funkhaus/style-guide/blob/master/template/js/site.js#L32-L90
样式
1 2 3 | svg path { fill: #000; } |
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | $(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
1 2 3 4 5 | .disabled { opacity: 0.4; filter: grayscale(100%); -webkit-filter: grayscale(100%); } |
这使它在大多数浏览器中都呈现浅灰色。在IE(也可能是Opera Mini,我还没有测试过)中,不透明度属性明显褪色,虽然它不是灰色的,但仍然看起来很不错。
这是一个带有两个不同的CSS类的示例,用于Twemoji铃声图标:原始(黄色),上面的"禁用"类,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | .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%); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <!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> |
或者你可以使用CSS
1 2 3 4 | .frame { background: blue; -webkit-mask: url(image.svg) center / contain no-repeat; } |
如果您可以在页面中包含文件(PHP包括或通过您选择的CMS包含),您可以添加SVG代码并将其包含在您的页面中。这与将SVG源粘贴到页面中的工作方式相同,但使页面标记更清晰。
好处是你可以通过CSS定位部分SVG悬停 - 不需要javascript。
http://codepen.io/chriscoyier/pen/evcBu
你只需要使用这样的CSS规则:
1 | #pathidorclass:hover { fill: #303 !important; } |
请注意,
@Drew Baker为解决问题提供了很好的解决方案。代码工作正常。但是,那些使用AngularJs的人可能会发现很多依赖于jQuery。因此,我认为粘贴AngularJS用户是一个好主意,这是一个遵循@Drew Baker解决方案的代码。
AngularJs的代码方式相同
1. Html:在你的html文件中使用bellow标签:
1 | <svg-image src="/icons/my.svg" class="any-class-you-wish"></svg-image> |
2.指令:这将是您需要识别标签的指令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | '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:
1 2 3 4 5 | .any-class-you-wish{ border: 1px solid red; height: 300px; width: 120px } |
4.用业力茉莉花进行单元测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | '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]); }); }); |
我意识到你想用CSS完成这个,但只是提醒一下,如果它是一个小而简单的图像 - 你总是可以在Notepad ++中打开它并改变路径/ whateverelement的填充:
1 2 3 | <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"/> |
它可以节省大量丑陋的剧本。对不起,如果它是偏离基础的,但有时可以忽略简单的解决方案。
...甚至交换多个svg图像的大小可能比这个问题的一些代码片段小。
我写了一个指令来解决AngularJS的这个问题。它可以在这里找到 - ngReusableSvg。
它在渲染后替换SVG元素,并将其置于
用法很简单:
1 2 3 4 5 6 7 | <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> |
之后,您可以轻松拥有:
1 2 3 | .svg-class svg { fill: red; // whichever color you want } |
这是基于接受的答案的
重要说明:它确实需要jQuery来替换,但我认为它可能对某些人有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 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'); } }; |
然后只需将
此解决方案完全用SVG替换
有一个名为SVGInject的开源库,它使用
这是使用SVGInject的最小示例:
1 2 3 4 5 6 7 8 | <html> <head> <script src="svg-inject.min.js"> </head> <body> <img src="image.svg" onload="SVGInject(this)" /> </body> </html> |
加载图像后,
它解决了SVG注入的几个问题:
注射完成后,可以隐藏SVG。如果在加载时已经应用了样式,则这很重要,否则会导致短暂的"无格式内容闪烁"。
如果SVG被多次注入,则随机字符串被添加到SVG中的每个ID,以避免在文档中多次具有相同的ID。
SVGInject是简单的Javascript,适用于所有支持SVG的浏览器。
免责声明:我是SVGInject的合着者
这是一个没有框架的代码,只有纯粹的js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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) }) |
如果我们有更多这样的svg图像,我们也可以借助font-files。
像https://glyphter.com/这样的网站可以从我们的svgs获取一个字体文件。
例如。
1 2 3 4 5 6 7 8 9 | @font-face { font-family: 'iconFont'; src: url('iconFont.eot'); } #target{ color: white; font-size:96px; font-family:iconFont; } |
您可以使用数据图像。使用数据图像(data-URI),您可以像内联一样访问SVG。
这是使用纯CSS和SVG的翻转效果。
我知道它很乱,但你可以这样做。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | .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; } |
1 | |
您可以在此处将svg转换为数据网址
由于SVG基本上是代码,因此您只需要内容。我使用PHP来获取内容,但您可以使用任何您想要的内容。
1 2 3 | <?php $content = file_get_contents($pathToSVG); ?> |
然后,我在div容器中"按原样"打印内容
1 | <?php echo $content;?> |
最终在CSS上将规则设置为容器的SVG子项
1 2 3 | .fill-class > svg { fill: orange; } |
我用一个材料图标SVG得到了这个结果:
如果您希望jQuery处理DOM中的所有svg元素并且DOM的大小合理,则所选解决方案很好。但是如果您的DOM很大并且您决定动态加载DOM的一部分,那么仅仅为了更新svg元素而重新扫描整个DOM实际上是没有意义的。相反,使用jQuery插件来执行此操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /** * 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 = $('').append(svg.clone()).html(); ctx.replaceWith(newHtml); }); return this; }; }(jQuery)); |
在你的html中,指定一个svg元素,如下所示:
1 | <svg src="images/someSvgFile.svg" height="45" width="45" class="mySVGClass"/> |
并应用插件:
1 | $(".mySVGClass").svgLoader(); |
for:悬停事件动画我们可以将样式保留在svg文件中,
像一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <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> |
在svgshare上查看这个
如果这是静态更改,则在Adobe Illustrator(或任何合适的SVG编辑器)中打开SVG文件,更改颜色并保存。