如何改变颜色的SVG图像使用CSS (jQuery SVG图像替换)?

这是一个自我的Q& a的一段方便的代码,我想出了。

目前,还没有一种简单的方法来嵌入SVG图像,然后通过CSS访问SVG元素。使用JS SVG框架有多种方法,但如果您所做的只是制作一个带有翻转状态的简单图标,那么这些方法就过于复杂了。

所以这就是我想到的,我认为这是迄今为止在网站上使用SVG文件的最简单的方法。它的概念来自于早期的文本到图像替换方法,但据我所知,还从未用于svg。

问题是这样的:

我如何在CSS中嵌入SVG并改变其颜色而不使用JS-SVG框架?

752673 次浏览

首先,在HTML中使用IMG标记来嵌入SVG图形。我使用Adobe Illustrator来制作图形。

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

这就像你如何嵌入一个普通的图像。注意,您需要将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,并将其替换为链接文件中的内联svg。最大的优势是它允许你现在使用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 < /强> < / p > 我们有一个更复杂的版本,包括缓存: https://github.com/funkhaus/style-guide/blob/master/template/js/site.js#L32-L90 < /强> < / p >

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

这样做的好处是,您可以通过CSS将SVG的某些部分用于悬停—不需要javascript。

http://codepen.io/chriscoyier/pen/evcBu < a href = " http://codepen.io/chriscoyier/pen/evcBu " > < / >

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

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

注意,!important位是覆盖填充颜色所必需的。

或者你也可以使用CSS mask,虽然浏览器支持不是很好,但你可以使用一个备用方案

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

@Drew Baker给出了一个很好的解决方案。代码正常工作。然而,那些使用AngularJs的人可能会发现很多依赖于jQuery。因此,我认为为AngularJS用户粘贴@Drew Baker的解决方案的代码是个好主意。

AngularJs的相同代码

1. 超文本标记语言:在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. 单元测试与业力茉莉:

'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]);
});
});
如果我们有更多这样的svg图像,我们还可以借助font-files 像https://glyphter.com/这样的网站可以从我们的svgs中获得一个字体文件

如。

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

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

它在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 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 filter属性(包括Edge,但不包括IE11)。它适用于SVG图像和其他元素。你可以使用hue-rotateinvert来修改颜色,尽管它们不允许你单独修改不同的颜色。我使用下面的CSS类来显示一个图标的“禁用”版本(其中原始是一个饱和颜色的SVG图片):

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

这使得它在大多数浏览器中呈浅灰色。在IE中(可能还有我没有测试过的Opera Mini),它会因为不透明属性而明显褪色,尽管不是灰色,但看起来仍然很不错。

下面是一个例子,有四个不同的CSS类用于Twemoji钟形图标:original(黄色),上面的“禁用”类,hue-rotate(绿色)和invert(蓝色)。

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

下面是基于已接受答案的knockout.js版本:

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

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标签。

这个解决方案完全用SVG替换了img标记,任何额外的绑定都不会被尊重。

如果您希望jQuery处理DOM中的所有svg元素,并且DOM的大小合理,那么所选的解决方案是很好的。但是如果您的DOM很大,并且您决定动态加载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 == 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)
})

我知道你想用CSS来完成这个,但只是一个提醒,以防它是一个小的,简单的图像-你可以随时在notepad++中弹出它,并更改路径/whatever元素的填充:

<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图像也可能比这个问题的一些代码片段更小。

你可以使用data-image。使用data-image(data-URI),您可以像内联一样访问SVG。

下面是使用纯CSS和SVG的滚动效果。

我知道它混乱的,但你可以这样做。

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

因为SVG基本上是代码,所以您只需要内容。我使用PHP来获取内容,但您可以使用任何您想要的内容。

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

然后,我已经打印内容“是”在一个div容器

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

最后将规则设置为CSS上的容器的SVG子元素

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

我用SVG材质图标得到了这个结果:

  1. Firefox 59.0.2(64位)Linux

enter image description here

  1. 谷歌Chrome66.0.3359.181 (Build official)(64位)Linux

enter image description here

  1. Opera 53.0.2907.37 Linux

enter image description here

for:悬停事件动画我们可以在SVG文件内留下样式, 像一个< / p >

<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上检查这个

有一个叫做SVGInject的开源库,它使用onload属性来触发注入。你可以在https://github.com/iconfu/svg-inject找到GitHub项目

下面是一个使用SVGInject的最小示例:

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

图像加载后,onload="SVGInject(this)将触发注入,并且<img>元素将被src属性中提供的SVG文件的内容所取代。

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

  1. svg可以隐藏,直到注射完成。如果在加载时已经应用了样式,这就很重要,否则会导致简短的“无样式内容闪光”。

  2. <img>元素自动注入自身。如果动态添加svg,就不必担心再次调用注入函数。

  3. 向SVG中的每个ID添加一个随机字符串,以避免在多次注入SVG时在文档中多次使用相同的ID。

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

声明:我是SVGInject的合著者

TL/DR:去这里-> https://codepen.io/sosuke/pen/Pjoqqp

解释:

我假设你有这样的html:

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

绝对要走过滤路线。您的SVG很可能是黑色或白色的。你可以应用一个过滤器,让它成为你想要的任何颜色,例如,我有一个黑色的svg,我想要薄荷绿。我首先将它反转为白色(这在技术上是所有RGB颜色完全),然后玩色调饱和度等。正确的做法:

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

更好的是,你可以使用一个工具将你想要的十六进制转换为你的过滤器:https://codepen.io/sosuke/pen/Pjoqqp

.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颜色:fill='rgb(3,122,247)'