tag manipulation img color change css svg gradient

css - manipulation - ¿Cómo puedo referirme a una definición de degradado interno dentro de un símbolo de sprite SVG?



svg on img tag (2)

RESUMEN: Un sprite SVG contiene cinco bloques de icono <symbol> , uno de los cuales hace referencia a su propia definición de gradiente por ID. Ya no puede encontrar este gradiente y renderizar correctamente.

JSFIDDLE: http://jsfiddle.net/Qtq24/1/

Estoy cambiando algunos gráficos a SVG, y como son iconos (en este caso para los perfiles de redes sociales) me gustaría mantenerlos en un sprite (como lo había hecho antes con PNG).

He seguido esta guía de sprites SVG en CSS-tricks.com (junto con este seguimiento que aconseja utilizar <symbol> lugar de <g> ).

Ahora tengo un archivo sprite SVG, social-sprite.svg , que puede ver en su totalidad here .

Este es un bloque <svg> completo que contiene cinco bloques <symbol> diferentes, cada uno con un id y un atributo viewBox . En cada caso, obtuve el código SVG para cada símbolo al preparar íconos oficiales en Adobe Illustrator y conservar las partes relevantes del código procesado.

El archivo .svg se incluye a través de PHP tan pronto como se abre la etiqueta <body> (y es por eso que el contenedor principal <svg> está marcado con style="display: none;" ) para que las referencias a cada símbolo funcionen. desde el HTML.

Cuatro iconos funcionan perfectamente, y el único con el que tengo problemas es el icono de YouTube, porque utiliza un degradado definido internamente. Aquí está la parte de YouTube del código SVG:

<symbol id="youtube" viewBox="0 0 400 281.641"> <path id="Triangle" fill="#FFFFFF" d="M159.845,191.73l106.152-54.999L159.845,81.348V191.73z"/> <path id="The_Sharpness" opacity="0.12" fill-rule="evenodd" clip-rule="evenodd" fill="#420000" d="M159.845,81.348l93.091,62.162 l13.061-6.778L159.845,81.348z"/> <g id="Lozenge"> <g> <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="200.4204" y1="2.6162" x2="200.4204" y2="278.9292"> <stop offset="0" style="stop-color:#E52D27"/> <stop offset="1" style="stop-color:#BF171D"/> </linearGradient> <path fill="url(#SVGID_1_)" d="M392.928,62.226c0,0-3.839-27.073-15.617-38.995C362.371,7.583,345.626,7.506,337.947,6.59 c-54.975-3.974-137.441-3.974-137.441-3.974h-0.171c0,0-82.464,0-137.44,3.974c-7.68,0.916-24.419,0.993-39.364,16.641 C11.753,35.153,7.92,62.226,7.92,62.226s-3.929,31.792-3.929,63.583v29.805c0,31.791,3.929,63.582,3.929,63.582 s3.833,27.073,15.611,38.995c14.945,15.646,34.575,15.152,43.318,16.792c31.43,3.015,133.571,3.946,133.571,3.946 s82.552-0.124,137.526-4.099c7.679-0.915,24.424-0.993,39.363-16.64c11.778-11.922,15.617-38.995,15.617-38.995 s3.923-31.791,3.923-63.582v-29.805C396.851,94.017,392.928,62.226,392.928,62.226z M159.863,191.73l-0.018-110.383 l106.152,55.384L159.863,191.73z"/> </g> </g> </symbol>

Y esto se llama en el HTML con:

<svg width="30" height="21"> <use xlink:href="#youtube" src="fallback.png" width="30" height="21" /> </svg>

La apertura de dos rutas funciona bien, el problema es que en este nuevo archivo SVG de sprite combinado, con cada icono separado como un <symbol> , el "Lozenge" <path> no puede encontrar la referencia # SVGID_1_ al <linearGradient> .

En Firefox, esto hace que la pastilla se muestre en blanco (supongo que tal vez no se muestre en absoluto, realmente no la he visto):

mientras que Chrome lo hace en negro:

Obviamente ninguno de los dos es aceptable. Lo único que puedo hacer en este momento es eliminar fill="url(#SVGID_1_)" en la ruta y simplemente rellenar con un color plano rojo apropiado al logotipo de YouTube. Sin embargo, esta no es una solución adecuada, incluso descartando el hecho de que no se aceptará de manera adecuada el logotipo de YouTube de esta manera según las pautas de su marca.

Cosas que he probado (y no tuve suerte con):

  • eliminando los dos <g> envoltorios que rodean el degradado y la ruta, por lo que todo el símbolo es simplemente <path>-<path>-<linearGradient>-<path>
  • envolviendo la definición de gradiente dentro de un contenedor <defs>
  • envolviéndolo en un <defs> y también moviéndolo a la parte superior del archivo SVG, es decir, fuera de los límites del <symbol> específico de YouTube
  • cambio de nombre de identificación (nunca se sabe)
  • redefiniendo el gradiente con porcentajes en lugar de valores de píxeles

Entonces, ¿cómo obtengo un <symbol> ya interno para hacer referencia a una definición <linearGradient> también interna?

EDITAR: Resulta que el gradiente falla cuando todo el bloque <svg> está marcado con style="display: none;" . Si se elimina este estilo, el degradado se procesa correctamente. Pero como recordatorio, este estilo se agrega para que al importar el sprite SVG no se muestre instantáneamente en la página, y solo le permita hacer referencias a los símbolos definidos como identificadores según sea necesario.

visibility: hidden u opacity: 0 permite que el gradiente se reproduzca correctamente, obviamente no ofrecen soluciones adecuadas, ya que aún demarcan el espacio que el SVG habría ocupado si estuviera visible.

Después de descubrir todo esto, estaba bastante seguro de que no sería un problema tener el <svg> completamente visible sin estilos añadidos DENTRO de un contenedor <div> que está oculto. Sin embargo, incluso esto hace que el gradiente no se renderice. No estoy más cerca de resolver el problema.


En primer lugar, tenga en cuenta la edición de mi pregunta, después de lo cual descubro que el uso de la display: none para ocultar los símbolos SVG hasta que los necesitamos fue el problema.

Seguí jugueteando y me decidí por esta "respuesta", que está lejos de ser perfecta, pero aún debería ser confiable para cualquier situación de este tipo.

Todo lo que necesita hacer es envolver todo el código <svg> en un contenedor <div> que debe mostrarse pero nunca afectará el diseño , así que lo hice a través de un mega exceso de CSS como:

height: 0; width: 0; position: absolute; visibility: hidden;

Y esto funciona muy bien. Vea el último violín: http://jsfiddle.net/Qtq24/5/

Si alguien tiene una solución mejor, me encantaría escucharla, ya que se siente como una forma de hacerlo, pero supongo que no es más hacky que tener que usar display: none; de todas formas.


Tienes dos problemas:

No use style = "display: none;" en SVG. Lo tienes en el elemento raíz <svg> . O visibilidad: oculta, altura / anchura = "0" o <defs> son mejores alternativas.

Hay un error en Firefox que los elementos de degradado no funcionan si están dentro de los símbolos. Sin embargo, la solución es bastante simple, simplemente mueva su Agente lineal fuera del símbolo para que se vea así ...

<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="200.4204" y1="2.6162" x2="200.4204" y2="278.9292"> <stop offset="0" style="stop-color:#E52D27"/> <stop offset="1" style="stop-color:#BF171D"/> </linearGradient> <symbol id="youtube" viewBox="0 0 400 281.641"> <path id="Triangle" fill="#FFFFFF" d="M159.845,191.73l106.152-54.999L159.845,81.348V191.73z"/> <path id="The_Sharpness" opacity="0.12" fill-rule="evenodd" clip-rule="evenodd" fill="#420000" d="M159.845,81.348l93.091,62.162 l13.061-6.778L159.845,81.348z"/> <g id="Lozenge"> <g> <path fill="url(#SVGID_1_)" d="M392.928,62.226c0,0-3.839-27.073-15.617-38.995C362.371,7.583,345.626,7.506,337.947,6.59 c-54.975-3.974-137.441-3.974-137.441-3.974h-0.171c0,0-82.464,0-137.44,3.974c-7.68,0.916-24.419,0.993-39.364,16.641 C11.753,35.153,7.92,62.226,7.92,62.226s-3.929,31.792-3.929,63.583v29.805c0,31.791,3.929,63.582,3.929,63.582 s3.833,27.073,15.611,38.995c14.945,15.646,34.575,15.152,43.318,16.792c31.43,3.015,133.571,3.946,133.571,3.946 s82.552-0.124,137.526-4.099c7.679-0.915,24.424-0.993,39.363-16.64c11.778-11.922,15.617-38.995,15.617-38.995 s3.923-31.791,3.923-63.582v-29.805C396.851,94.017,392.928,62.226,392.928,62.226z M159.863,191.73l-0.018-110.383 l106.152,55.384L159.863,191.73z"/> </g> </g> </symbol>