Como alterar a cor da imagem SVG usando CSS (substituição de imagem SVG jQuery)?

Este é um auto Q & A de um pedaço de código acessível eu vim com.

Atualmente, não há uma maneira fácil de incorporar uma imagem SVG e depois ter access aos elementos SVG via CSS. Existem vários methods de usar estruturas SVG JS, mas eles são muito complicados se tudo o que você está fazendo é criar um ícone simples com um estado de sobreposição.

Então, aqui está o que eu criei, que eu acho que é de longe a maneira mais fácil de usar arquivos SVG em um site. Ele usa seu conceito dos primeiros methods de substituição de texto para imagem, mas, até onde sei, nunca foi feito para SVGs.

Esta é a questão:

Como incorporar um SVG e alterar sua cor em CSS sem usar uma estrutura JS-SVG?

Em primeiro lugar, use uma tag IMG no seu HTML para incorporar um gráfico SVG. Eu usei o Adobe Illustrator para fazer o gráfico.

 

Isto é exatamente como você embutiria uma imagem normal. Note que você precisa definir o IMG para ter uma class de svg. A class ‘social-link’ é apenas por exemplo. O ID não é obrigatório, mas é útil.

Em seguida, use este código jQuery (em um arquivo separado ou inline no 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 classs 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'); }); 

O que o código acima faz é procurar todos os IMGs com a class ‘svg’ e substituí-lo pelo SVG embutido do arquivo vinculado. A enorme vantagem é que ele permite que você use CSS para mudar a cor do SVG agora, assim:

 svg:hover path { fill: red; } 

O código jQuery que eu escrevi também portas através do ID de imagens originais e classs. Então este CSS funciona também:

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

Ou:

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

Você pode ver um exemplo dele trabalhando aqui: http://labs.funkhausdesign.com/examples/img-svg/img-to-svg.html

Temos uma versão mais complicada que inclui o armazenamento em cache aqui: https://github.com/funkhaus/style-guide/blob/master/template/js/site.js#L32-L90

Estilo

 svg path { fill: #000; } 

Roteiro

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

Se você puder include arquivos (include ou include o PHP através do seu CMS de sua escolha) em sua página, poderá adicionar o código SVG e incluí-lo na sua página. Isso funciona da mesma forma que colar a origem SVG na página, mas torna a marcação de página mais limpa.

O benefício é que você pode direcionar partes do seu SVG via CSS para passar o mouse – não é necessário JavaScript.

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

Você só precisa usar uma regra de CSS como esta:

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

Observe que o bit !important é necessário para replace a cor de preenchimento.

Como alternativa, você poderia usar a mask CSS, o suporte concedido ao navegador não é bom, mas você poderia usar um fallback

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

Agora você pode usar a propriedade de filter CSS na maioria dos navegadores modernos (incluindo o Edge, mas não o IE11). Funciona em imagens SVG, bem como em outros elementos. Você pode usar hue-rotate ou inverter para modificar colors, embora elas não permitam modificar colors diferentes independentemente. Eu uso a seguinte class CSS para mostrar uma versão “desativada” de um ícone (onde o original é uma imagem SVG com colors saturadas):

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

Isso torna cinza claro na maioria dos navegadores. No IE (e provavelmente no Opera Mini, que eu não testei), ele é visivelmente enfraquecido pela propriedade opacity, que ainda parece muito boa, embora não seja cinza.

Aqui está um exemplo com quatro classs CSS diferentes para o ícone do sino Twemoji : original (amarelo), a class “desativada” acima, hue-rotate (verde) e invert (azul).

 .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%); } 
            

@Drew Baker deu uma ótima solução para resolver o problema. O código funciona corretamente. No entanto, aqueles que usam o AngularJs podem encontrar muita dependência do jQuery. Consequentemente, achei uma boa ideia colar os usuários do AngularJS, um código seguindo a solução do @Drew Baker.

AngularJs caminho do mesmo código

1. Html : use a tag abaixo em seu arquivo html:

  

2. Directiva : esta será a directiva que terá de reconhecer a etiqueta:

 '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 classs = 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. Teste unitário com 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(''); element = $compile(element)(scope); spyOn(scope, 'manipulateImgNode').andCallThrough(); $httpBackend.whenGET(apiUrl + 'me').respond(200, {}); data = '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + ''; $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 classs', function () { $httpBackend.flush(); var result = scope.manipulateImgNode(data, element); var classList = ["svg"]; expect(result.classList[0]).toBe(classList[0]); }); }); 

Eu percebo que você está querendo fazer isso com CSS, mas apenas um lembrete no caso de ser uma imagem pequena e simples – você pode sempre abrir no Notepad ++ e mudar o preenchimento do caminho / selfelement:

  

Poderia salvar uma tonelada de roteiro feio. Desculpe se é fora da base, mas às vezes as soluções simples podem ser negligenciadas.

… mesmo a troca de várias imagens svg pode ser menor em tamanho do que alguns dos trechos de código para esta questão.

Eu escrevi uma diretiva para resolver esse problema com o AngularJS. Está disponível aqui – ngReusableSvg .

Ele substitui o elemento SVG depois que ele é renderizado e o coloca dentro de um elemento div , tornando seu CSS facilmente alterável. Isso ajuda a usar o mesmo arquivo SVG em locais diferentes usando tamanhos / colors diferentes.

O uso é simples:

   

Depois disso, você pode facilmente ter:

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

Aqui está uma versão para o knockout.js base na resposta aceita:

Importante: Ele realmente requer o jQuery também para a substituição, mas achei que pode ser útil para alguns.

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

Em seguida, basta aplicar data-bind="svgConvert: true" à sua tag img.

Esta solução substitui completamente a tag img por um SVG e quaisquer ligações adicionais não seriam respeitadas.

Aqui está um código no framework, apenas js puro:

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

Se tivermos um número maior de tais imagens svg, também podemos obter a ajuda de arquivos de fonts.
Sites como o https://glyphter.com/ podem nos obter um arquivo de fonte de nossos svgs.


Por exemplo

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

A solução selecionada é adequada se você quiser que o jQuery processe todos os elementos svg no seu DOM e que seu DOM tenha um tamanho razoável. Mas se o seu DOM é grande e você decide carregar partes do seu DOM dinamicamente, não faz sentido ter de verificar novamente todo o DOM apenas para atualizar os elementos svg. Em vez disso, use um plugin jQuery para fazer isso:

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

Em seu html, especifique um elemento svg da seguinte forma:

  

E aplique o plugin:

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

Como o SVG é basicamente código, você precisa apenas de conteúdo. Eu usei PHP para obter conteúdo, mas você pode usar o que quiser.

  

Então, imprimi o conteúdo “como está” dentro de um contêiner div

 

Para configurar finnaly regra para SVG childs do contêiner em CSS

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

Eu obtive este resultado com um ícone de material SVG:

  1. Mozilla Firefox 59.0.2 (64 bits) Linux

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui

  1. Opera 53.0.2907.37 Linux

insira a descrição da imagem aqui

Você pode usar dados de imagem para isso. Usando dados de imagem (data-URI), você pode acessar o SVG como inline.

Aqui está o efeito de rollover usando CSS e SVG puros.

Eu sei que é uma bagunça, mas você pode fazer isso.

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

para: hover event animations podemos deixar os estilos dentro do arquivo svg, como um

       

verifique isso no svgshare

Se esta for uma alteração estática, abra o arquivo SVG no Adobe Illustrator (ou qualquer outro editor SVG adequado) altere a cor e salve-a.