SVG incorporato in CSS


285

È possibile utilizzare una definizione SVG inline nei CSS?

Intendo qualcosa come:

.my-class {
  background-image: <svg>...</svg>;
}

1
Cosa stai cercando di fare, aggiungere l'immagine "fonte" al foglio di stile?
Zuul,

1
Fai attenzione che le soluzioni proposte non funzioneranno per immagini CSS, <img>tag HTML e altri casi se SVG è un mix di più immagini (a meno che non sia incorporato), vedi SVG di immagini di sfondo con maschera che utilizza immagini esterne non funzionanti e restrizioni specifiche su SVG usate come un'immagine .
Skippy le Grand Gourou,

Risposte:


377

Sì, è possibile. Prova questo:

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

(Si noti che il contenuto SVG deve essere evaso dall'URL affinché funzioni, ad esempio #viene sostituito con %23.)

Funziona con IE 9 (che supporta SVG) . Gli URL dei dati funzionano anche nelle versioni precedenti di IE (con limitazioni), ma non supportano nativamente SVG.


8
L'unico browser in cui sembra funzionare bene è Safari (5.1.4). In Opera 11.62 il gradiente è nero, in IE 9 e Firefox 12 è bianco. In Chrome 19, funziona A MENO CHE non specifichi la larghezza / altezza dell'SVG in% unità. Direi che è più una stranezza che una vera caratteristica. È comunque una bella scoperta.
toniedzwiedz,

4
Giusto ... comunque sono ansioso di vedere gli sguardi sui volti dei miei colleghi quando mostro loro un piccolo mostro carino come questo, quindi grazie ancora per aver mostrato che è possibile. Sono appena andato alle specifiche standard e ho dichiarato che era praticamente impossibile, che si è rivelato essere un errore (una specie di)
toniedzwiedz,

18
L '"incompatibilità del browser" qui è principalmente solo la mancanza di una corretta evasione dell'URL, tutto all'interno url()dovrebbe essere evaso dall'URL . Vedi jsfiddle.net/6WAtQ per un esempio che funziona perfettamente su Opera, Firefox e Safari.
Erik Dahlström,

3
C'è qualche differenza di compatibilità tra svg con codifica base64 e non base64? Base64 gonfia il mio file css, sto pensando di usare solo inline svgs ..
enapupe

4
Nota, il modo standard per specificare il set di caratteri è con "; charset = UTF-8" invece di "; utf8". tools.ietf.org/html/rfc2397
Keith Shaw,

240

Un po 'in ritardo, ma se qualcuno di voi sta impazzendo nel tentativo di utilizzare SVG in linea come sfondo , i suggerimenti di fuga sopra non funzionano. Per uno, non funziona in IE e, a seconda del contenuto del tuo SVG, la tecnica causerà problemi in altri browser, come FF.

Se base64 codifica lo svg (non l'intero URL, solo il tag svg e il suo contenuto!) Funziona in tutti i browser. Ecco lo stesso esempio di jsfiddle in base64: http://jsfiddle.net/vPA9z/3/

Il CSS ora ha questo aspetto:

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

Ricorda di rimuovere qualsiasi URL che fuoriesca prima di convertirlo in base64. In altre parole, l'esempio sopra mostrava color = '# fcc' convertito in color = '% 23fcc', dovresti tornare a #.

Il motivo per cui base64 funziona meglio è che elimina tutti i problemi con virgolette singole e doppie e escape dell'URL

Se stai usando JS, puoi usare window.btoa()per produrre il tuo svg base64; e se non funziona (potrebbe lamentarsi di caratteri non validi nella stringa), puoi semplicemente usare https://www.base64encode.org/ .

Esempio per impostare uno sfondo 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 puoi generare SVG al volo, anche modificandone i parametri.

Uno degli articoli migliori sull'uso di SVG è qui: http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

Spero che questo ti aiuti

Mike


2
Grazie uomo. La soluzione con Base64 ha funzionato in modo eccellente, mentre ho avuto problemi con la risposta accettata.
Marcel,

1
Mi hai salvato la vita. Avevo un'immagine di bordo SVG che funzionava in Chrome ma non su FF. Ora funziona! : D
Papipo,

Mi ha aiutato anche (dopo aver perso tempo a provare la risposta accettata) - questa dovrebbe essere sicuramente la risposta accettata.
Katai,

Se questo non funziona ancora per te - assicurati di avere l' xmlnsattributo impostato su svgelement prima di codificare base64 come i <svg xmlns="http://www.w3.org/2000/svg">...</svg>browser a volte lo spezzano senza di esso quando svg è direttamente in HTML - questo non è il caso :)
jave.web

Nel caso in cui qualcuno stia ancora cercando questa risposta 6+ anni dopo: Probabilmente non dovresti basare 64
Volker E.

38

Per le persone che stanno ancora lottando, sono riuscito a farlo funzionare su tutti i browser moderni IE11 e versioni successive.

base64 non era un'opzione per me perché volevo usare SASS per generare icone SVG basate su un dato colore. Ad esempio: in @include svg_icon(heart, #FF0000);questo modo posso creare una certa icona in qualsiasi colore e devo solo incorporare la forma SVG nel CSS. (con Base64 dovresti incorporare l'SVG in ogni singolo colore che vuoi usare)

Ci sono tre cose di cui devi essere consapevole:

  1. URL CODIFICARE IL TUO SVG Come altri hanno suggerito, è necessario codificare l'URL dell'intera stringa SVG affinché funzioni in IE11. Nel mio caso, ho lasciato fuori i valori di colore in campi come fill="#00FF00"e stroke="#FF0000"e li ho sostituiti con una variabile SASS in fill="#{$color-rgb}"modo che questi possano essere sostituiti con il colore che desidero. Puoi utilizzare qualsiasi convertitore online per codificare l'URL nel resto della stringa. Ti ritroverai con una stringa SVG come questa:

    % 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. OMITARE IL CHARSET UTF8 NELL'URL DEI DATI Quando si crea l'URL dei dati, è necessario escludere il set di caratteri affinché funzioni in IE11.

    Immagine di sfondo NON : url (dati: immagine / svg + xml; utf-8,% 3Csvg% 2 ....)
    MA immagine di sfondo: url (dati: immagine / svg + xml,% 3Csvg% 2 ... .)


  1. USA RGB () INSTEAD OF HEX colors A Firefox non piace # nel codice SVG. Quindi è necessario sostituire i valori esadecimali del colore con quelli RGB.

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

Nel mio caso uso SASS per convertire un dato esadecimale in un valore rgb valido. Come sottolineato nei commenti, è meglio codificare anche l'URL della stringa RGB (quindi la virgola diventa% 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');
   }
}

Mi rendo conto che questa potrebbe non essere la soluzione migliore per SVG molto complessi (SVG in linea non lo è mai in quel caso), ma per icone piatte con solo un paio di colori funziona davvero alla grande.

Sono stato in grado di tralasciare un'intera bitmap di sprite e sostituirla con SVG in linea nel mio CSS, che si è rivelato essere solo circa 25 kb dopo la compressione. Quindi è un ottimo modo per limitare la quantità di richieste che il tuo sito deve fare, senza gonfiare il tuo file CSS.


1
A proposito, correggimi se sbaglio ma rgb(255,0,0)dovrebbe essere rgb(255%2C0%2C0)codificato una volta.
Capsule

1
Volevo dire che non codifico la stringa RGB e funziona ancora. Ma codificarlo come hai detto è probabilmente meglio.
Davy Baert,

1
Bene, in realtà, ho appena testato e %23ff0000funziona benissimo #ff0000in Firefox
Capsule

1
@Capsule Non so cosa stia succedendo, ma% 23ff0000 è l'UNICO metodo che funziona per me sia su Chrome che su FF. # ff0000 non funziona e nemmeno i metodi RGB (255,0,0) e rgb (255% 2C0% 2C0).
Ideogram,

1
Un metodo (incluso il codice SCSS) che richiede meno codifica: codepen.io/jakob-e/pen/doMoML
Sphinxxx

26

Su Mac / Linux, puoi facilmente convertire un file SVG in un valore codificato base64 per l'attributo di sfondo CSS con questo semplice comando bash:

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

Testato su Mac OS X. In questo modo si evita anche il disordine di escape dell'URL.

Ricorda che la codifica base64 di un file SVG ne aumenta le dimensioni, vedi il post sul blog di css-tricks.com .


2
Ai lettori: si prega di commentare la propria opinione anziché semplicemente votare in basso, quindi questa risposta può essere migliorata con la collaborazione! La collaborazione è essenziale in siti di domande e risposte come questo. Grazie!
araks,

2
@LorDex il link che hai fornito nel tuo commento è lo stesso che è nella mia risposta :)
arabi

10

Ho creato una demo di CodePen che ha avuto lo stesso problema con l'integrazione di SVG inline nei CSS. Una soluzione che funziona con SCSS è quella di creare una semplice funzione di codifica URL.

Una funzione di sostituzione della stringa può essere creata dalle funzioni str-slice e str-index integrate (vedi css-tricks , grazie a Hugo Giraudel).

Poi, basta sostituire %, <,> , ", ', con i %xxcodici:

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

C'è anche una image-inlinefunzione di aiuto disponibile in Compass, ma poiché non è supportata in CodePen, questa soluzione potrebbe probabilmente essere utile.

Demo su CodePen: http://codepen.io/terabaud/details/PZdaJo/


1
Ho anche creato una penna che ti consente di convertire le stringhe svg in un valore di sfondo css corretto: s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb Quindi, fondamentalmente, incolli <svg><path></svg>nella textarea superiore e genererai direttamente il percorso disinfettato all'interno di un url()valore.
LukyVj,

1
Questo ha funzionato alla grande. Grazie. Una nota. Devi usare; charset = utf8 per farlo funzionare in IE.
Daniel Lefebvre,

4

L'SVG in linea proveniente da fonti di terze parti (come i grafici di Google) potrebbe non contenere l'attributo dello spazio dei nomi XML (xmlns="http://www.w3.org/2000/svg" ) nell'elemento SVG (o forse viene rimosso dopo il rendering dell'SVG - né il browser inspector né i comandi jQuery dalla console del browser mostrano lo spazio dei nomi nell'elemento SVG).

Quando devi riutilizzare questi snippet svg per le tue altre esigenze (immagine di sfondo in CSS o elemento img in HTML) fai attenzione allo spazio dei nomi mancante. Senza lo spazio dei nomi, i browser potrebbero rifiutare di visualizzare SVG (indipendentemente dalla codifica utf8 o base64).


4

Ho trovato una soluzione per SVG. Ma funziona solo per Webkit, voglio solo condividere la mia soluzione con te. Nel mio esempio viene mostrato come utilizzare l'elemento SVG da DOM come sfondo attraverso un filtro (background-image: url ('# glyph') non funziona).

Le funzionalità necessarie per il rendering di questa icona SVG:

  1. Applicazione degli effetti del filtro SVG agli elementi HTML mediante CSS (IE e Edge non supportano)
  2. feImage supporto del carico di frammenti (Firefox non supporta)

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

Un'altra soluzione, è utilizzare la codifica 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>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.