¿Cómo cambiar el color de la imagen SVG usando CSS (reemplazo de imagen jQuery SVG)?

Este es un auto Q & A de una pieza útil de código que se me ocurrió.

Actualmente, no hay una manera fácil de insertar una imagen SVG y luego tener acceso a los elementos SVG a través de CSS. Existen varios métodos para utilizar marcos JS SVG, pero son demasiado complicados si todo lo que hace es crear un icono simple con un estado de sustitución.

Así que esto es lo que se me ocurrió, que creo que es, de lejos, la forma más fácil de usar archivos SVG en un sitio web. Toma su concepto de los primeros métodos de reemplazo de texto a imagen, pero hasta donde yo sé, nunca se ha hecho para los SVG.

Esta es la pregunta:

¿Cómo incrusto un SVG y cambio su color en CSS sin usar un marco JS-SVG?

En primer lugar, use una etiqueta IMG en su HTML para incrustar un gráfico SVG. Usé Adobe Illustrator para hacer el gráfico.

 

Esto es como si insertaras una imagen normal. Tenga en cuenta que debe configurar el IMG para que tenga una clase de svg. La clase ‘enlace social’ es solo por ejemplos. La identificación no es obligatoria, pero es útil.

Luego use este código jQuery (en un archivo separado o en línea en 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'); }); 

Lo que hace el código anterior es buscar todos los IMG con la clase ‘svg’ y reemplazarlos con el SVG en línea del archivo vinculado. La ventaja masiva es que le permite usar CSS para cambiar el color del SVG ahora, así:

 svg:hover path { fill: red; } 

El código jQuery también escribí puertos en las ID y clases de las imágenes originales. Entonces este CSS también funciona:

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

O:

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

Puede ver un ejemplo de cómo funciona aquí: http://labs.funkhausdesign.com/examples/img-svg/img-to-svg.html

Tenemos una versión más complicada que incluye el almacenamiento en caché aquí: https://github.com/funkhaus/style-guide/blob/master/template/js/site.js#L32-L90

Estilo

 svg path { fill: #000; } 

Guión

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

Si puede incluir archivos (incluya o incluya PHP a través de su CMS de su elección) en su página, puede agregar el código SVG e incluirlo en su página. Esto funciona igual que pegar la fuente SVG en la página, pero hace que el marcado de la página sea más limpio.

El beneficio es que puede orientar partes de su SVG a través de CSS para desplazarse – no se requiere Javascript.

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

Solo tienes que usar una regla de CSS como esta:

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

Tenga en cuenta que el bit !important es necesario para anular el color de relleno.

Alternativamente, podría usar mask CSS, el soporte del navegador otorgado no es bueno, pero podría usar un respaldo

 .frame { background: blue; -webkit-mask: url(https://stackoverflow.com/questions/11978995/how-to-change-color-of-svg-image-using-css-jquery-svg-image-replacement/image.svg) center / contain no-repeat; } 

Ahora puede usar la propiedad de filter CSS en la mayoría de los navegadores modernos (incluido Edge, pero no IE11). Funciona en imágenes SVG, así como en otros elementos. Puede usar hue-rotate o invert para modificar los colores, aunque no le permiten modificar diferentes colores de forma independiente. Uso la siguiente clase de CSS para mostrar una versión “desactivada” de un ícono (donde el original es una imagen SVG con un color saturado):

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

Esto hace que sea gris claro en la mayoría de los navegadores. En IE (y probablemente Opera Mini, que no he probado) se desvanece notablemente por la propiedad de opacidad, que todavía se ve bastante bien, aunque no es gris.

Aquí hay un ejemplo con cuatro clases de CSS diferentes para el icono de campana de Twemoji : original (amarillo), la clase “desactivada” anterior, 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%); } 
 < !DOCTYPE html>           

@Drew Baker dio una gran solución para resolver el problema. El código funciona correctamente Sin embargo, aquellos que usan AngularJs pueden encontrar mucha dependencia en jQuery. En consecuencia, pensé que era una buena idea pegar para los usuarios de AngularJS, un código que sigue la solución de @Drew Baker.

Modo AngularJs del mismo código

1. Html : usa la etiqueta de abajo en tu archivo html:

  

2. Directiva : esta será la directiva que deberá reconocer la 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 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. Prueba de unidad con 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 = '< ?xml version="1.0" encoding="utf-8"?>' + '' + '< !DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + '' + '' + '' + '' + '' + '' + '' + ''; $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]); }); }); 

Me doy cuenta de que quieres lograr esto con CSS, pero solo un recordatorio en caso de que sea una imagen pequeña y simple: siempre puedes abrirla en Notepad ++ y cambiar el relleno de path / whateverelement:

  

Podría ahorrar una tonelada de guiones feos. Lo siento si está fuera de la base, pero a veces las soluciones simples pueden pasarse por alto.

… incluso el intercambio de varias imágenes svg puede ser de menor tamaño que algunos fragmentos de código para esta pregunta.

Escribí una directiva para resolver este problema con AngularJS. Está disponible aquí – ngReusableSvg .

Sustituye el elemento SVG después de que se ha procesado y lo coloca dentro de un elemento div , lo que hace que su CSS sea fácilmente modificable. Esto ayuda a usar el mismo archivo SVG en diferentes lugares usando diferentes tamaños / colores.

El uso es simple:

   

Después de eso, puedes tener fácilmente:

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

Aquí hay una versión para knockout.js basada en la respuesta aceptada:

Importante: realmente requiere jQuery también para el reemplazo, pero pensé que podría ser útil para algunos.

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

Luego solo aplica data-bind="svgConvert: true" a tu etiqueta img.

Esta solución reemplaza completamente la etiqueta img con un SVG y no se respetarán los enlaces adicionales.

Aquí hay un código sin marco, solo 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) }) 

Si tenemos una mayor cantidad de tales imágenes svg también podemos tomar la ayuda de archivos de fonts.
Los sitios como https://glyphter.com/ pueden obtener un archivo de fuente de nuestra svgs.


P.ej

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

Hay una biblioteca de código abierto llamada SVGInject que usa el atributo onload para activar la inyección. Puede encontrar el proyecto GitHub en https://github.com/iconfu/svg-inject

Aquí hay un ejemplo mínimo usando SVGInject:

         

Después de cargar la imagen, onload="SVGInject(this) activará la inyección y el elemento será reemplazado por el contenido del archivo SVG provisto en el atributo src .

Resuelve varios problemas con la inyección de SVG:

  1. Los SVG se pueden ocultar hasta que la inyección haya finalizado. Esto es importante si ya se aplica un estilo durante el tiempo de carga, que de lo contrario causaría un breve “destello de contenido sin estilo”.

  2. Los elementos inyectan de manera automática. Si agrega SVG dinámicamente, no tiene que preocuparse por volver a llamar a la función de inyección.

  3. Se agrega una cadena aleatoria a cada ID en el SVG para evitar tener el mismo ID varias veces en el documento si se inyecta un SVG más de una vez.

SVGInject es Javascript simple y funciona con todos los navegadores compatibles con SVG.

Descargo de responsabilidad: soy el coautor de SVGInject

La solución seleccionada está bien si quieres que jQuery procese todos los elementos svg en tu DOM y tu DOM tenga un tamaño razonable. Pero si tu DOM es grande y decides cargar partes de tu DOM dinámicamente, realmente no tiene sentido tener que volver a escanear todo el DOM solo para actualizar los elementos svg. En su lugar, use un plugin jQuery para hacer esto:

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

En tu html, especifica un elemento svg de la siguiente manera:

  

Y aplica el plugin:

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

Como SVG es básicamente código, solo necesitas contenidos. Usé PHP para obtener contenido, pero puedes usar lo que quieras.

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

Luego, imprimí contenido “tal como está” dentro de un contenedor div

 
< ?php echo $content;?>

Para establecer finalmente la regla a los hijos SVG del contenedor en CSS

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

Obtuve estos resultados con un icono de material SVG:

  1. Mozilla Firefox 59.0.2 (64 bits) 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

Puedes usar data-image para eso. usando data-image (data-URI) puede acceder a SVG como en línea.

Aquí está el efecto de renovación utilizando CSS puro y SVG.

Lo sé sucio pero puedes hacerlo de esta manera.

  .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: animaciones de eventos hover podemos dejar los estilos dentro de archivo svg, como un

       

mira esto en svgshare

Si se trata de un cambio estático, abra el archivo SVG en Adobe Illustrator (o cualquier editor SVG adecuado) cambie el color y guárdelo.