Inline-SVG in CSS

283

Ist es möglich, eine Inline-SVG-Definition in CSS zu verwenden?

Ich meine so etwas wie:

.my-class {
  background-image: <svg>...</svg>;
}
akaRem
quelle
1
Was versuchst du zu tun, füge das Bild "Quelle" dem Stylesheet hinzu?
Zuul
1
Hüten Sie sich vor , dass die vorgeschlagenen Lösungen nicht funktionieren für CSS Bilder, HTML - <img>Tags und anderen Fällen , wenn der SVG eine Mischung aus mehreren Bildern ist (es sei denn , eingebettet), siehe Hintergrundbild SVG mit Maske mit externen Bild nicht funktioniert und insbesondere Beschränkungen für SVG verwendet als ein Bild .
Skippy le Grand Gourou

Antworten:

374

Ja, es ist möglich. Versuche dies:

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

(Beachten Sie, dass der SVG-Inhalt mit einer URL versehen werden muss, damit dies funktioniert, z . B. #durch ersetzt wird %23.)

Dies funktioniert in IE 9 (das SVG unterstützt) . Daten-URLs funktionieren auch in älteren IE-Versionen (mit Einschränkungen), unterstützen SVG jedoch nicht von Haus aus.

Raab
quelle
8
Der einzige Browser, in dem es gut zu funktionieren scheint, ist Safari (5.1.4). In Opera 11.62 ist der Farbverlauf schwarz, in IE 9 und Firefox 12 weiß. In Chrome 19 funktioniert es, es sei denn, Sie geben die Breite / Höhe des SVG in% an. Ich würde sagen, es ist eher eine Kuriosität als ein echtes Feature. Es ist allerdings ein cooler Fund.
Toniedzwiedz
4
Richtig ... trotzdem bin ich gespannt auf die Gesichter meiner Kollegen, wenn ich ihnen ein süßes kleines Monster wie dieses zeige. Nochmals vielen Dank, dass Sie gezeigt haben, dass es möglich ist. Ich ging gerade zur Standardspezifikation und erklärte, es sei praktisch unmöglich, was sich als Fehler herausstellte
toniedzwiedz
18
Die "Browser-Inkompatibilität" hier ist meistens nur ein Mangel an korrekter URL- url()Escape-Funktion. Alles, was sich darin befindet, sollte URL-maskiert sein. Unter jsfiddle.net/6WAtQ finden Sie ein Beispiel, das in Opera, Firefox und Safari einwandfrei funktioniert.
Erik Dahlström
3
Gibt es einen Kompatibilitätsunterschied zwischen base64-codiertem SVG und Nicht-Base64? Base64 bläht meine CSS-Datei auf, ich denke, ich verwende nur Inline-SVGs.
Enapupe
4
Beachten Sie, dass der Zeichensatz standardmäßig mit "; charset = UTF-8" anstelle von "; utf8" angegeben wird. tools.ietf.org/html/rfc2397
Keith Shaw
240

Ein bisschen spät, aber wenn einer von Ihnen verrückt geworden ist und versucht hat, Inline-SVG als Hintergrund zu verwenden , funktionieren die oben genannten Vorschläge nicht ganz. Zum einen funktioniert es nicht im IE, und je nach Inhalt Ihres SVG verursacht die Technik Probleme in anderen Browsern wie FF.

Wenn Sie das svg mit base64 codieren (nicht die gesamte URL, nur das svg-Tag und seinen Inhalt!), Funktioniert es in allen Browsern. Hier ist das gleiche jsfiddle-Beispiel in base64: http://jsfiddle.net/vPA9z/3/

Das CSS sieht jetzt so aus:

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

Denken Sie daran, alle entweichenden URLs zu entfernen, bevor Sie zu base64 konvertieren. Mit anderen Worten, das obige Beispiel zeigte color = '# fcc' konvertiert in color = '% 23fcc'. Sie sollten zu # zurückkehren.

Der Grund, warum base64 besser funktioniert, besteht darin, dass alle Probleme mit einfachen und doppelten Anführungszeichen und dem Entkommen von URLs beseitigt werden

Wenn Sie JS verwenden, können Sie damit window.btoa()Ihr base64-SVG erstellen. und wenn es nicht funktioniert (es könnte sich über ungültige Zeichen in der Zeichenfolge beschweren), können Sie einfach https://www.base64encode.org/ verwenden .

Beispiel zum Festlegen eines Div-Hintergrunds:

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>

Mit JS können Sie SVGs im laufenden Betrieb generieren und sogar deren Parameter ändern.

Einer der besseren Artikel zur Verwendung von SVG ist hier: http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

Hoffe das hilft

Mike

Mike Tommasi
quelle
2
Danke, Mann. Die Lösung mit Base64 funktionierte hervorragend, während ich Probleme mit der akzeptierten Antwort hatte.
Marcel
1
Du hast mein Leben gerettet. Ich hatte ein SVG-Rahmenbild, das in Chrom arbeitete, aber nicht in FF. Jetzt gehts! : D
Papipo
Hat mir auch geholfen (nachdem ich Zeit verloren hatte, die akzeptierte Antwort auszuprobieren) - dies sollte definitiv die akzeptierte Antwort sein.
Katai
Wenn dies bei Ihnen immer noch nicht funktioniert - stellen Sie sicher, dass Sie das xmlnsAttribut auf svgelement gesetzt haben, bevor Sie base64-codieren, wie <svg xmlns="http://www.w3.org/2000/svg">...</svg>Browser es manchmal ohne es
aufteilen,
Falls sich 6+ Jahre später noch jemand diese Antwort ansieht: Sie sollten wahrscheinlich nicht base64 SVGs css-tricks.com/probably-dont-base64-svg
Volker E.
38

Für Leute, die immer noch Probleme haben, habe ich es geschafft, dies auf allen modernen Browsern IE11 und höher zum Laufen zu bringen.

base64 war für mich keine Option, da ich SASS verwenden wollte, um SVG-Symbole basierend auf einer bestimmten Farbe zu generieren. Beispiel: Auf @include svg_icon(heart, #FF0000);diese Weise kann ich ein bestimmtes Symbol in einer beliebigen Farbe erstellen und muss die SVG-Form nur einmal in das CSS einbetten. (Mit base64 müssten Sie das SVG in jede einzelne Farbe einbetten, die Sie verwenden möchten.)

Es gibt drei Dinge, die Sie beachten müssen:

  1. URL ENCODE YOUR SVG Wie andere vorgeschlagen haben, müssen Sie Ihre gesamte SVG-Zeichenfolge per URL codieren, damit sie in IE11 funktioniert. In meinem Fall habe ich die Farbwerte in Feldern wie fill="#00FF00"und stroke="#FF0000"weggelassen und sie durch eine SASS-Variable ersetzt, fill="#{$color-rgb}"damit diese durch die gewünschte Farbe ersetzt werden können. Sie können jeden Online-Konverter verwenden , um den Rest der Zeichenfolge per URL zu codieren. Am Ende erhalten Sie eine SVG-Zeichenfolge wie folgt:

    % 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. Lassen Sie den UTF8-Zeichensatz in der Daten-URL weg. Wenn Sie Ihre Daten-URL erstellen, müssen Sie den Zeichensatz weglassen, damit er in IE11 funktioniert.

    NICHT Hintergrundbild: URL (Daten: Bild / svg + xml; utf-8,% 3Csvg% 2 ....)
    ABER Hintergrundbild: URL (Daten: Bild / svg + xml,% 3Csvg% 2 ... .)


  1. VERWENDEN SIE RGB () STATT HEX-Farben Firefox mag # im SVG-Code nicht. Sie müssen also Ihre Farbhex-Werte durch RGB-Werte ersetzen.

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

In meinem Fall verwende ich SASS, um ein bestimmtes Hex in einen gültigen RGB-Wert umzuwandeln. Wie in den Kommentaren erwähnt, ist es am besten, auch Ihre RGB-Zeichenfolge per URL zu codieren (Komma wird also zu% 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');
   }
}

Mir ist klar, dass dies möglicherweise nicht die beste Lösung für sehr komplexe SVGs ist (Inline-SVGs gibt es in diesem Fall nie), aber für flache Symbole mit nur wenigen Farben funktioniert dies wirklich hervorragend.

Ich konnte eine ganze Sprite-Bitmap weglassen und in meinem CSS durch Inline-SVG ersetzen, was sich nach der Komprimierung als nur etwa 25 KB herausstellte. Auf diese Weise können Sie die Anzahl der Anfragen auf Ihrer Website begrenzen, ohne Ihre CSS-Datei aufzublähen.

Davy Baert
quelle
1
Btw, korrigieren Sie mich , wenn ich falsch bin , aber rgb(255,0,0)sollte sich rgb(255%2C0%2C0)einmal kodiert.
Kapsel
1
Ich meinte, dass ich die RGB-Zeichenfolge nicht codiere und sie immer noch funktioniert. Aber es ist wahrscheinlich besser, es zu codieren, wie Sie es erwähnt haben.
Davy Baert
1
Nun, eigentlich habe ich gerade getestet und %23ff0000funktioniert gut für #ff0000in Firefox
Capsule
1
@Capsule Ich weiß nicht, was passiert, aber% 23ff0000 ist die EINZIGE Methode, die für mich sowohl in Chrome als auch in FF funktioniert. # ff0000 funktioniert nicht und die Methoden RGB (255,0,0) und rgb (255% 2C0% 2C0) auch nicht.
Ideogramm
1
Eine Methode (einschließlich SCSS-Code), die weniger Codierung erfordert: codepen.io/jakob-e/pen/doMoML
Sphinxxx
26

Unter Mac / Linux können Sie eine SVG-Datei mit diesem einfachen bash-Befehl einfach in einen base64-codierten Wert für das CSS-Hintergrundattribut konvertieren:

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

Getestet unter Mac OS X. Auf diese Weise vermeiden Sie auch, dass die URL dem Chaos entgeht.

Denken Sie daran, dass die Base64-Codierung einer SVG-Datei ihre Größe erhöht (siehe Blogbeitrag von css-tricks.com) .

Araks
quelle
2
An die Leser: Bitte kommentieren Sie Ihre Meinung, anstatt nur abzustimmen, damit diese Antwort durch Ihre Zusammenarbeit verbessert werden kann! Bei solchen Fragen und Antworten ist die Zusammenarbeit unerlässlich. Danke dir!
Araks
2
@ LorDex der Link, den Sie in Ihrem Kommentar angegeben haben, ist der gleiche, der in meiner Antwort steht :)
araks
10

Ich habe eine CodePen-Demo erstellt, die das gleiche Problem beim Einbetten von Inline-SVG in CSS hatte. Eine Lösung, die mit SCSS funktioniert, besteht darin, eine einfache URL-Codierungsfunktion zu erstellen.

Eine String-Ersetzungsfunktion kann aus den integrierten str-Slice- und str-Index-Funktionen erstellt werden (siehe CSS-Tricks dank Hugo Giraudel).

Dann ersetzen Sie einfach %, <, >, ", ', mit den %xxCodes:

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

image-inlineIn Compass ist auch eine Hilfsfunktion verfügbar. Da diese in CodePen jedoch nicht unterstützt wird, ist diese Lösung möglicherweise hilfreich.

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

Lea Rosema
quelle
1
Ich habe auch einen Stift erstellt, mit dem Sie SVG-Zeichenfolgen in einen richtigen CSS-Hintergrundwert konvertieren können: s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb Im Grunde fügen Sie Ihren Stift<svg><path></svg> in den oberen Textbereich ein und er gibt den bereinigten Pfad direkt aus innerhalb eines url()Wertes.
LukyVj
1
Das hat super funktioniert. Danke dir. Eine Note. Sie müssen; charset = utf8 verwenden, damit dies im IE funktioniert.
Daniel Lefebvre
4

Inline-SVG aus Quellen von Drittanbietern (wie Google Charts) enthält möglicherweise kein XML-Namespace-Attribut ( xmlns="http://www.w3.org/2000/svg") im SVG-Element (oder wird nach dem Rendern von SVG entfernt - weder der Browser Inspector noch die jQuery-Befehle von der Browserkonsole zeigen den Namespace im SVG-Element an).

Wenn Sie diese SVG-Snippets für Ihre anderen Anforderungen (Hintergrundbild in CSS oder IMG-Element in HTML) neu verwenden müssen, achten Sie auf den fehlenden Namespace. Ohne den Namespace können Browser die Anzeige von SVG verweigern (unabhängig von der Codierung utf8 oder base64).

mp31415
quelle
4

Ich habe eine Lösung für SVG gefunden. Aber es funktioniert nur für Webkit. Ich möchte nur meine Problemumgehung mit Ihnen teilen. In meinem Beispiel wird gezeigt, wie das SVG-Element aus DOM als Hintergrund durch einen Filter verwendet wird (Hintergrundbild: URL ('# Glyphe') funktioniert nicht).

Funktionen, die für das Rendern dieses SVG-Symbols benötigt werden:

  1. Anwenden von SVG-Filtereffekten auf HTML-Elemente mithilfe von CSS (IE und Edge werden nicht unterstützt)
  2. Unterstützung für das Laden von FeImage-Fragmenten (Firefox unterstützt nicht)

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

Eine weitere Lösung ist die Verwendung der URL-Codierung

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
quelle