SVG en línea en CSS

284

¿Es posible usar una definición SVG en línea en CSS?

Me refiero a algo como:

.my-class {
  background-image: <svg>...</svg>;
}
akaRem
fuente
1
¿Qué estás tratando de hacer, agregar la imagen "fuente" a la hoja de estilo?
Zuul
1
Tenga en cuenta que las soluciones propuestas no funcionarán para imágenes CSS, <img>etiquetas HTML y otros casos si el SVG es una mezcla de varias imágenes (a menos que esté incrustado), vea el SVG de la imagen de fondo con máscara usando una imagen externa que no funciona , y específicamente restricciones en el SVG utilizado como una imagen .
Skippy le Grand Gourou

Respuestas:

376

Sí, es posible. Prueba esto:

body { background-image: 
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='%23F00'/><stop offset='90%' stop-color='%23fcc'/> </linearGradient><rect fill='url(%23gradient)' x='0' y='0' width='100%' height='100%'/></svg>");
      }

(Tenga en cuenta que el contenido SVG debe ser escapado de URL para que esto funcione, por ejemplo, #se reemplaza con %23).

Esto funciona en IE 9 (que admite SVG) . Las URL de datos también funcionan en versiones anteriores de IE (con limitaciones), pero no son compatibles de forma nativa con SVG.

Raab
fuente
8
El único navegador en el que parece funcionar bien es Safari (5.1.4). En Opera 11.62 el gradiente es negro, en IE 9 y Firefox 12 es blanco. En Chrome 19, funciona A MENOS que especifique el ancho / alto del SVG en% de unidades. Diría que es más una rareza que una característica real. Sin embargo, es un hallazgo genial.
toniedzwiedz
44
Bien ... todavía estoy ansioso por ver las miradas en las caras de mis compañeros de trabajo cuando les muestro un pequeño monstruo lindo como este, así que gracias de nuevo por mostrar que es posible. Simplemente fui a la especificación estándar y dije que era prácticamente imposible, lo que resultó ser un error (más o menos)
toniedzwiedz
18
La "incompatibilidad del navegador" aquí es principalmente la falta de un escape de URL adecuado, todo lo que url()hay dentro debe escapar de la URL . Consulte jsfiddle.net/6WAtQ para ver un ejemplo que funciona bien en Opera, Firefox y Safari.
Erik Dahlström
3
¿Hay alguna diferencia de compatibilidad entre svg codificado en base64 a no base64? Base64 hincha mi archivo css, estoy pensando en usar svgs en línea ...
enapupe
44
Tenga en cuenta que la forma estándar de especificar el juego de caracteres es con "; charset = UTF-8" en lugar de "; utf8". tools.ietf.org/html/rfc2397
Keith Shaw
240

Un poco tarde, pero si alguno de ustedes se ha vuelto loco tratando de usar SVG en línea como fondo , las sugerencias de escape anteriores no funcionan del todo. Por un lado, no funciona en IE, y dependiendo del contenido de su SVG, la técnica causará problemas en otros navegadores, como FF.

Si codifica base64 el svg (¡no toda la url, solo la etiqueta svg y su contenido!) Funciona en todos los navegadores. Aquí está el mismo ejemplo de jsfiddle en base64: http://jsfiddle.net/vPA9z/3/

El CSS ahora se ve así:

body { background-image: 
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PGxpbmVhckdyYWRpZW50IGlkPSdncmFkaWVudCc+PHN0b3Agb2Zmc2V0PScxMCUnIHN0b3AtY29sb3I9JyNGMDAnLz48c3RvcCBvZmZzZXQ9JzkwJScgc3RvcC1jb2xvcj0nI2ZjYycvPiA8L2xpbmVhckdyYWRpZW50PjxyZWN0IGZpbGw9J3VybCgjZ3JhZGllbnQpJyB4PScwJyB5PScwJyB3aWR0aD0nMTAwJScgaGVpZ2h0PScxMDAlJy8+PC9zdmc+");

Recuerde eliminar cualquier escape de URL antes de convertir a base64. En otras palabras, el ejemplo anterior mostró color = '# fcc' convertido a color = '% 23fcc', debe volver a #.

La razón por la que base64 funciona mejor es que elimina todos los problemas con comillas simples y dobles y escape de URL

Si está utilizando JS, puede usarlo window.btoa()para producir su svg base64; y si no funciona (puede quejarse de caracteres no válidos en la cadena), simplemente puede usar https://www.base64encode.org/ .

Ejemplo para establecer un fondo div:

var mySVG = "<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='#F00'/><stop offset='90%' stop-color='#fcc'/> </linearGradient><rect fill='url(#gradient)' x='0' y='0' width='100%' height='100%'/></svg>";
var mySVG64 = window.btoa(mySVG);
document.getElementById('myDiv').style.backgroundImage = "url('data:image/svg+xml;base64," + mySVG64 + "')";
html, body, #myDiv {
  width: 100%;
  height: 100%;
  margin: 0;
}
<div id="myDiv"></div>

Con JS puede generar SVG sobre la marcha, incluso cambiando sus parámetros.

Uno de los mejores artículos sobre el uso de SVG está aquí: http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

Espero que esto ayude

Miguel

Mike Tommasi
fuente
2
Gracias hombre. La solución con Base64 funcionó excelente, mientras que tuve problemas con la respuesta aceptada.
Marcel
1
Me salvaste la vida. Tenía una imagen de borde SVG que funcionaba en Chrome pero no en FF. ¡Ahora funciona! : D
Papipo
También me ayudó (después de perder tiempo probando la respuesta aceptada), esta definitivamente debería ser la respuesta aceptada.
Katai
Si esto aún no funciona para usted, asegúrese de tener el xmlnsatributo establecido como svgelemento antes de codificar en base64, como los <svg xmlns="http://www.w3.org/2000/svg">...</svg>navegadores a veces lo fragmentan sin él cuando svg está directamente en HTML; este NO es el caso :)
jave.web
En caso de que alguien todavía esté mirando esta respuesta más de 6 años después: Probablemente no debería basar64
Volker E.
38

Para las personas que todavía están luchando, logré hacer que esto funcione en todos los navegadores modernos IE11 y superiores.

base64 no era una opción para mí porque quería usar SASS para generar íconos SVG basados ​​en cualquier color. Por ejemplo: de @include svg_icon(heart, #FF0000);esta manera puedo crear un icono determinado en cualquier color, y solo tengo que incrustar la forma SVG una vez en el CSS. (con base64 tendrías que incrustar el SVG en cada color que quieras usar)

Hay tres cosas que debe tener en cuenta:

  1. URL ENCODE SU SVG Como otros han sugerido, necesita codificar en URL su cadena SVG completa para que funcione en IE11. En mi caso, omití los valores de color en campos como fill="#00FF00"y stroke="#FF0000"y los reemplacé con una variable SASS fill="#{$color-rgb}"para que estos puedan reemplazarse con el color que quiero. Puede usar cualquier convertidor en línea para codificar URL en el resto de la cadena. Terminarás con una cadena SVG como esta:

    % 3Csvg% 20xmlns% 3D% 27http% 3A% 2F% 2Fwww.w3.org% 2F2000% 2Fsvg% 27% 20viewBox% 3D% 270% 200% 20494.572% 20494.572% 27% 20width% 3D% 27512% 27% 20height% 3D % 27512% 27% 3E% 0A% 20% 20% 3Cpath% 20d% 3D% 27M257.063% 200C127.136% 200% 2021.808% 20105.33% 2021.808% 20235.266c0% 2041.012% 2010.535% 2079.541% 2028.973% 20113.104L3.825 % 20464.586c345% 2012.797% 2041.813% 2012.797% 2015.467% 200% 2029.872-4.721% 2041.813-12.797v158.184z% 27% 20fill% 3D% 27 # {$ color-rgb} % 27% 2F% 3E% 3C% 2Fsvg% 3E


  1. OMITE EL CHARSET UTF8 EN LA URL DE DATOS Al crear su URL de datos, debe omitir el conjunto de caracteres para que funcione en IE11.

    NO imagen de fondo: url (datos: imagen / svg + xml; utf-8,% 3Csvg% 2 ....)
    PERO imagen de fondo: url (datos: imagen / svg + xml,% 3Csvg% 2 ... .)


  1. USE RGB () EN LUGAR DE colores HEX. A Firefox no le gusta # en el código SVG. Por lo tanto, debe reemplazar sus valores hexadecimales de color con valores RGB.

    NOT fill = "# FF0000"
    PERO fill = "rgb (255,0,0)"

En mi caso, uso SASS para convertir un hexadecimal dado a un valor rgb válido. Como se señaló en los comentarios, también es mejor codificar en URL su cadena RGB (para que la coma se convierta en% 2C)

@mixin svg_icon($id, $color) {
   $color-rgb: "rgb(" + red($color) + "%2C" + green($color) + "%2C" + blue($color) + ")";
   @if $id == heart {
      background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20494.572%20494.572%27%20width%3D%27512%27%20height%3D%27512%27%3E%0A%20%20%3Cpath%20d%3D%27M257.063%200C127.136%200%2021.808%20105.33%2021.808%20235.266c0%204%27%20fill%3D%27#{$color-rgb}%27%2F%3E%3C%2Fsvg%3E');
   }
}

Me doy cuenta de que esta podría no ser la mejor solución para SVG muy complejos (SVG en línea nunca lo es en ese caso), pero para los iconos planos con solo un par de colores, esto realmente funciona muy bien.

Pude dejar de lado un mapa de bits de sprite completo y reemplazarlo con SVG en línea en mi CSS, que resultó ser solo alrededor de 25 kb después de la compresión. Por lo tanto, es una excelente manera de limitar la cantidad de solicitudes que tiene que hacer su sitio, sin inflar su archivo CSS.

Davy Baert
fuente
1
Por cierto, corrígeme si me equivoco, pero rgb(255,0,0)debería rgb(255%2C0%2C0)codificarse una vez.
Cápsula
1
Quise decir que no codifico la cadena RGB y todavía funciona. Pero codificarlo como mencionaste probablemente sea mejor.
Davy Baert
1
Bueno, en realidad, acabo de probar y %23ff0000funciona bien #ff0000en Firefox
Capsule
1
@Capsule No sé lo que está sucediendo, pero% 23ff0000 es el ÚNICO método que me funciona tanto en Chrome como en FF. # ff0000 no funciona, y tampoco lo hacen los métodos RGB (255,0,0) y rgb (255% 2C0% 2C0).
Ideograma
1
Un método (incluido el código SCSS) que requiere menos codificación: codepen.io/jakob-e/pen/doMoML
Sphinxxx
26

En Mac / Linux, puede convertir fácilmente un archivo SVG a un valor codificado en base64 para el atributo de fondo CSS con este simple comando bash:

echo "background: transparent url('data:image/svg+xml;base64,"$(openssl base64 < path/to/file.svg)"') no-repeat center center;"

Probado en Mac OS X. De esta manera, también evita que el URL se escape.

Recuerde que la codificación base64 de un archivo SVG aumenta su tamaño, vea la publicación de blog css-tricks.com .

araks
fuente
2
A los lectores: por favor comenten su opinión en lugar de simplemente votar, ¡para que esta respuesta se pueda mejorar con su colaboración! La colaboración es esencial en sitios de preguntas y respuestas como este. ¡Gracias!
araks 01 de
2
@LorDex el enlace que proporcionó en su comentario es el mismo que está en mi respuesta :)
araks
10

Bifurqué una demostración de CodePen que tenía el mismo problema al incrustar SVG en línea en CSS. Una solución que funciona con SCSS es construir una función simple de codificación de URL.

Se puede crear una función de reemplazo de cadena a partir de las funciones integradas str-slice, str-index (ver trucos css , gracias a Hugo Giraudel).

A continuación, basta con sustituir %, <, >, ", ', con los %xxcódigos:

@function svg-inline($string){
  $result: str-replace($string, "<svg", "<svg xmlns='http://www.w3.org/2000/svg'");
  $result: str-replace($result, '%', '%25');
  $result: str-replace($result, '"', '%22');
  $result: str-replace($result, "'", '%27');
  $result: str-replace($result, ' ', '%20');
  $result: str-replace($result, '<', '%3C');
  $result: str-replace($result, '>', '%3E');
  @return "data:image/svg+xml;utf8," + $result;
}

$mySVG: svg-inline("<svg>...</svg>");

html {
  height: 100vh;
  background: url($mySVG) 50% no-repeat;
}

También hay una image-inlinefunción auxiliar disponible en Compass, pero como no es compatible con CodePen, esta solución probablemente sea útil.

Demostración en CodePen: http://codepen.io/terabaud/details/PZdaJo/

Lea Rosema
fuente
1
También creé un bolígrafo que te permite convertir cadenas de svg en un valor de fondo css adecuado: s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb Entonces, básicamente, pegas tu <svg><path></svg>en el área de texto superior, y saldrá directamente a la ruta desinfectada dentro de un url()valor.
LukyVj
1
Esto funcionó de maravilla. Gracias. Una nota. Debe usar; charset = utf8 para que esto funcione en IE.
Daniel Lefebvre
4

Es posible que el SVG en línea proveniente de fuentes de terceros (como los gráficos de Google) no contenga el atributo del espacio de nombres XML ( xmlns="http://www.w3.org/2000/svg") en el elemento SVG (o tal vez se elimine una vez que se renderice SVG; ni el inspector del navegador ni los comandos jQuery de la consola del navegador muestran el espacio de nombres en el elemento SVG).

Cuando necesite cambiar el propósito de estos fragmentos de svg para sus otras necesidades (imagen de fondo en CSS o elemento img en HTML), tenga cuidado con el espacio de nombres que falta. Sin el espacio de nombres, los navegadores pueden negarse a mostrar SVG (independientemente de la codificación utf8 o base64).

mp31415
fuente
4

Encontré una solución para SVG. Pero solo funciona para Webkit, solo quiero compartir mi solución contigo. En mi ejemplo, se muestra cómo usar el elemento SVG de DOM como fondo a través de un filtro (background-image: url ('# glyph') no funciona).

Las características necesarias para este icono SVG rinden:

  1. Aplicación de efectos de filtro SVG a elementos HTML usando CSS (IE y Edge no son compatibles)
  2. Soporte de carga de fragmentos de imagen (Firefox no es compatible)

.test {
  /*  background-image: url('#glyph');
    background-size:100% 100%;*/
    filter: url(#image); 
    height:100px;
    width:100px;
}
.test:before {
   display:block;
   content:'';
   color:transparent;
}
.test2{
  width:100px;
  height:100px;
}
.test2:before {
   display:block;
   content:'';
   color:transparent;
   filter: url(#image); 
   height:100px;
   width:100px;
}
<svg style="height:0;width:0;" version="1.1" viewbox="0 0 100 100"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
 <defs>
     <g id="glyph">
          <path id="heart" d="M100 34.976c0 8.434-3.635 16.019-9.423 21.274h0.048l-31.25 31.25c-3.125 3.125-6.25 6.25-9.375 6.25s-6.25-3.125-9.375-6.25l-31.202-31.25c-5.788-5.255-9.423-12.84-9.423-21.274 0-15.865 12.861-28.726 28.726-28.726 8.434 0 16.019 3.635 21.274 9.423 5.255-5.788 12.84-9.423 21.274-9.423 15.865 0 28.726 12.861 28.726 28.726z" fill="crimson"/>
     </g>
    <svg id="resized-glyph"  x="0%" y="0%" width="24" height="24" viewBox="0 0 100 100" class="icon shape-codepen">
      <use xlink:href="#glyph"></use>
    </svg>
     <filter id="image">
       <feImage xlink:href="#resized-glyph" x="0%" y="0%" width="100%" height="100%" result="res"/>
       <feComposite operator="over" in="res" in2="SourceGraphic"/>
    </filter>
 </defs>
</svg>
<div class="test">
</div>
<div class="test2">
</div>

Una solución más, es usar codificación url

var container = document.querySelector(".container");
var svg = document.querySelector("svg");
var svgText = (new XMLSerializer()).serializeToString(svg);
container.style.backgroundImage = `url(data:image/svg+xml;utf8,${encodeURIComponent(svgText)})`;
.container{
  height:50px;
  width:250px;
  display:block;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: contain;
}
<svg  height="100" width="500" xmlns="http://www.w3.org/2000/svg">
    <ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" />
</svg>
<div class="container"></div>

Alex Nikulin
fuente