Inline SVG w CSS

284

Czy w CSS można używać wbudowanej definicji SVG?

Mam na myśli coś takiego:

.my-class {
  background-image: <svg>...</svg>;
}
akaRem
źródło
1
Co próbujesz zrobić, dodać obraz „źródło” do arkusza stylów?
Zuul
1
Uważaj, że proponowane rozwiązania nie będą działać dla obrazów CSS, <img>znaczników HTML i innych przypadków, jeśli SVG jest mieszanką kilku obrazów (chyba że osadzone), zobacz obraz tła SVG z maską z niedziałającym obrazem zewnętrznym , a w szczególności ograniczenia dotyczące SVG używanego jako obraz .
Skippy le Grand Gourou

Odpowiedzi:

376

Tak to mozliwe. Spróbuj tego:

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

(Zauważ, że treść SVG musi mieć zmiany znaczenia na adres URL, aby to zadziałało, np. #Zostanie zastąpione przez %23.)

Działa to w IE 9 (który obsługuje SVG) . Adresy URL danych działają również w starszych wersjach IE (z ograniczeniami), ale natywnie nie obsługują SVG.

Raab
źródło
8
Jedyną przeglądarką, w której wydaje się ładnie działać, jest Safari (5.1.4). W Operze 11.62 gradient jest czarny, w IE 9 i Firefox 12 jest biały. W Chrome 19 działa, JEŚLI nie określisz szerokości / wysokości SVG w% jednostkach. Powiedziałbym, że to bardziej osobliwość niż prawdziwa funkcja. To fajne znalezisko.
toniedzwiedz
4
Racja ... wciąż nie mogę się doczekać, aby zobaczyć miny moich współpracowników, kiedy pokazuję im takiego słodkiego małego potwora, więc jeszcze raz dziękuję za pokazanie, że to możliwe. Po prostu poszedłem do standardowej specyfikacji i stwierdziłem, że jest to praktycznie niemożliwe, co okazało się błędem (niejako)
toniedzwiedz
18
„Niekompatybilność przeglądarki” jest tutaj głównie brakiem poprawnej zmiany adresu URL, wszystko w środku url()powinno być oznaczone jako „url”. Zobacz jsfiddle.net/6WAtQ, aby zobaczyć przykład, który działa dobrze w Opera, Firefox i Safari.
Erik Dahlström
3
Czy jest jakaś różnica kompatybilności między svg zakodowanym w base64 a non-base64? Base64 wzdycha mój plik css, myślę, że po prostu użyj inline svgs ..
enapupe
4
Uwaga: standardowym sposobem określania zestawu znaków jest „; charset = UTF-8” zamiast „; utf8”. tools.ietf.org/html/rfc2397
Keith Shaw
240

Trochę późno, ale jeśli któryś z was oszalał, próbując użyć wbudowanego SVG jako tła , powyższe sugestie ucieczki nie działają. Po pierwsze, nie działa w IE, a w zależności od zawartości pliku SVG technika spowoduje problemy w innych przeglądarkach, takich jak FF.

Jeśli base64 kodujesz plik svg (nie cały adres URL, tylko znacznik svg i jego zawartość!), Działa on we wszystkich przeglądarkach. Oto ten sam przykład jsfiddle w base64: http://jsfiddle.net/vPA9z/3/

CSS wygląda teraz tak:

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

Pamiętaj, aby usunąć wszelkie znaki ucieczki przed konwersją na base64. Innymi słowy, powyższy przykład pokazał color = '# fcc' przekonwertowany na color = '% 23fcc', powróć do #.

Powodem, dla którego base64 działa lepiej, jest to, że eliminuje wszystkie problemy z pojedynczymi i podwójnymi cudzysłowami oraz ucieczką adresów URL

Jeśli używasz JS, możesz użyć go window.btoa()do wygenerowania pliku svg base64; a jeśli to nie działa (może narzekać na nieprawidłowe znaki w ciągu), możesz po prostu użyć https://www.base64encode.org/ .

Przykład ustawienia tła 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>

Dzięki JS możesz generować pliki SVG w locie, nawet zmieniając jego parametry.

Jeden z lepszych artykułów na temat korzystania z SVG znajduje się tutaj: http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

Mam nadzieję że to pomoże

Mikrofon

Mike Tommasi
źródło
2
Dzięki. Rozwiązanie z Base64 działało doskonale, a ja miałem problemy z zaakceptowaną odpowiedzią.
Marcel
1
Uratowałeś mi życie. Miałem obraz granicy SVG, który działał w chrome, ale nie w FF. Teraz działa! : D
Papipo
Pomógł mi również (po utracie czasu na wypróbowanie zaakceptowanej odpowiedzi) - zdecydowanie powinna to być zaakceptowana odpowiedź.
Katai
Jeśli to nadal nie działa dla Ciebie - upewnij się, że masz xmlnsustawiony atrybut svgelement przed kodowaniem base64, tak jak <svg xmlns="http://www.w3.org/2000/svg">...</svg>przeglądarki czasami go fragmentują, gdy svg jest bezpośrednio w HTML - tak nie jest :)
jave.web
W przypadku, gdy ktoś nadal patrzy na tę odpowiedź ponad 6 lat później: Prawdopodobnie nie powinieneś bazować na plikach
Volker E.
38

Dla osób, które wciąż mają problemy, udało mi się uruchomić to we wszystkich nowoczesnych przeglądarkach IE11 i nowszych.

base64 nie było dla mnie opcją, ponieważ chciałem użyć SASS do generowania ikon SVG w oparciu o dowolny kolor. Na przykład: W @include svg_icon(heart, #FF0000);ten sposób mogę utworzyć określoną ikonę w dowolnym kolorze i wystarczy osadzić kształt SVG tylko raz w CSS. (z base64 będziesz musiał osadzić SVG w każdym kolorze, którego chcesz użyć)

Należy pamiętać o trzech rzeczach:

  1. URL KODUJ SWOJE SVG Jak sugerują inni, musisz zakodować URL całego ciągu SVG, aby działał w IE11. W moim przypadku pominąłem wartości kolorów w polach takich jak fill="#00FF00"i stroke="#FF0000"zastąpiłem je zmienną SASS, fill="#{$color-rgb}"aby można je było zastąpić wybranym kolorem. Możesz użyć dowolnego konwertera online na adres URL kodujący resztę ciągu. Skończysz z ciągiem SVG takim jak ten:

    % 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% 20 wysokość% 3D % 27512% 27% 3E% 0A% 20% 20% 3 Ścieżka% 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% 20 wypełnienie% 3D% 27 # {$ color-rgb} % 27% 2F% 3E% 3C% 2Fsvg% 3E


  1. Pomiń zestaw znaków UTF8 w adresie URL danych Podczas tworzenia adresu URL danych musisz pominąć zestaw znaków, aby działał w IE11.

    NIE tło-obraz: adres URL (dane: image / svg + xml; utf-8,% 3Csvg% 2 ....)
    ALE obraz w tle: adres URL (dane: obraz / svg + xml,% 3Csvg% 2 ... .)


  1. UŻYJ RGB () zamiast kolorów HEX Firefox nie lubi # w kodzie SVG. Musisz więc zastąpić swoje wartości szesnastkowe koloru wartościami RGB.

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

W moim przypadku używam SASS do konwersji danego heksa na prawidłową wartość rgb. Jak wskazano w komentarzach, najlepiej również zakodować URL łańcucha RGB (przecinek staje się% 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');
   }
}

Zdaję sobie sprawę, że może to nie być najlepsze rozwiązanie w przypadku bardzo skomplikowanych plików SVG (w tym przypadku nigdy nie ma wbudowanego pliku SVG), ale w przypadku płaskich ikon z tylko kilkoma kolorami to naprawdę działa świetnie.

Byłem w stanie pominąć całą mapę bitową sprite i zastąpić ją wbudowanym SVG w moim CSS, który po kompresji okazał się mieć około 25 kb. Jest to więc świetny sposób na ograniczenie liczby żądań, które musi wykonać Twoja witryna, bez nadmuchiwania pliku CSS.

Davy Baert
źródło
1
Przy okazji popraw mnie, jeśli się mylę, ale rgb(255,0,0)powinien zostać rgb(255%2C0%2C0)raz zakodowany.
Kapsułka
1
Miałem na myśli, że nie koduję ciągu RGB i nadal działa. Ale kodowanie go, jak wspomniałeś, jest prawdopodobnie lepsze.
Davy Baert
1
Właściwie właśnie przetestowałem i %23ff0000działa dobrze #ff0000w przeglądarce Firefox
Capsule
1
@Capsule Nie wiem, co się dzieje, ale% 23ff0000 to jedyna metoda, która działa dla mnie zarówno w Chrome, jak i FF. # ff0000 nie działa, podobnie jak metody RGB (255,0,0) i rgb (255% 2C0% 2C0).
Ideogram
1
Metoda (w tym kod SCSS), która wymaga mniej kodowania: codepen.io/jakob-e/pen/doMoML
Sphinxxx
26

W systemie Mac / Linux można łatwo przekonwertować plik SVG na wartość zakodowaną w standardzie base64 dla atrybutu tła CSS za pomocą tego prostego polecenia bash:

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

Testowane na Mac OS X. W ten sposób unikniesz bałaganu uciekającego z adresu URL.

Pamiętaj, że kodowanie base64 pliku SVG zwiększa jego rozmiar, patrz post na blogu css-tricks.com .

araks
źródło
2
Do czytelników: skomentuj swoją opinię zamiast po prostu głosować, aby ta odpowiedź mogła zostać ulepszona dzięki współpracy! Współpraca jest niezbędna w takich witrynach z pytaniami i odpowiedziami. Dziękuję Ci!
araks
2
@LorDex link podany w komentarzu jest taki sam, jak w mojej odpowiedzi :)
araks 16.04.18
10

Rozwinąłem demo CodePen, które miało ten sam problem z osadzeniem wbudowanego SVG w CSS. Rozwiązaniem współpracującym z SCSS jest zbudowanie prostej funkcji kodowania adresu URL.

Funkcja zamiany łańcucha może być utworzona z wbudowanych funkcji str-slice, str-index (patrz sztuczki css , dzięki Hugo Giraudel).

Następnie, po prostu zastąpić %, <, >, ", ', z %xxkodami:

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

Istnieje również image-inlinefunkcja pomocnicza dostępna w Compass, ale ponieważ nie jest obsługiwana w CodePen, to rozwiązanie może być prawdopodobnie przydatne.

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

Lea Rosema
źródło
1
Stworzyłem również pióro, które pozwala przekonwertować ciągi svg na odpowiednią wartość tła css: s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb Tak więc, zasadniczo wklejasz się <svg><path></svg>do górnego obszaru tekstowego, a on bezpośrednio wyświetli oczyszczoną ścieżkę w ramach url()wartości.
LukyVj
1
To działało niesamowicie. Dziękuję Ci. Jedna uwaga. Musisz użyć; charset = utf8, aby to działało w IE.
Daniel Lefebvre
4

Wbudowany plik SVG pochodzący ze źródeł zewnętrznych (takich jak wykresy Google) może nie zawierać atrybutu przestrzeni nazw XML (xmlns="http://www.w3.org/2000/svg" ) w elemencie SVG (lub może zostać usunięty po renderowaniu SVG - ani inspektor przeglądarki, ani polecenia jQuery z konsoli przeglądarki nie wyświetlają przestrzeni nazw w elemencie SVG).

Gdy musisz zmienić przeznaczenie tych fragmentów svg na inne potrzeby (obraz tła w CSS lub element img w HTML), uważaj na brakującą przestrzeń nazw. Bez przestrzeni nazw przeglądarki mogą odmówić wyświetlania SVG (niezależnie od kodowania utf8 lub base64).

mp31415
źródło
4

Znalazłem jedno rozwiązanie dla SVG. Ale to działa tylko dla Webkit, chcę tylko podzielić się z tobą moim obejściem. W moim przykładzie pokazano, jak używać elementu SVG z DOM jako tła przez filtr (obraz w tle: url ('# glif') nie działa).

Funkcje potrzebne do renderowania tej ikony SVG:

  1. Stosowanie efektów filtrów SVG do elementów HTML za pomocą CSS (IE i Edge nie obsługują)
  2. Obsługa ładowania fragmentów feImage (Firefox nie obsługuje)

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

Jeszcze jednym rozwiązaniem jest użycie kodu 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
źródło