SVG sebaris dalam CSS

283

Apakah mungkin untuk menggunakan definisi SVG sebaris di CSS?

Maksud saya sesuatu seperti:

.my-class {
  background-image: <svg>...</svg>;
}
akaRem
sumber
1
Apa yang Anda coba lakukan, tambahkan "sumber" gambar ke lembar gaya?
Zuul
1
Berhati-hatilah bahwa solusi yang diusulkan tidak akan berfungsi untuk gambar CSS, <img>tag HTML, dan kasus lainnya jika SVG merupakan campuran dari beberapa gambar (kecuali tertanam), lihat gambar latar belakang SVG dengan mask menggunakan gambar eksternal tidak berfungsi , dan secara khusus pembatasan pada SVG digunakan sebagai sebuah gambar .
Skippy le Grand Gourou

Jawaban:

375

Ya itu mungkin. Coba ini:

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

(Perhatikan bahwa konten SVG perlu dilepaskan dengan url agar ini berfungsi, misalnya #diganti dengan %23.)

Ini berfungsi di IE 9 (yang mendukung SVG) . Data-URL juga berfungsi dalam versi IE lama (dengan keterbatasan), tetapi mereka tidak mendukung SVG.

Raab
sumber
8
Satu-satunya browser yang tampaknya berfungsi dengan baik adalah Safari (5.1.4). Di Opera 11.62 gradiennya hitam, di IE 9 dan Firefox 12 warnanya putih. Di Chrome 19, berfungsi KECUALI Anda menentukan lebar / tinggi SVG dalam% unit. Saya akan mengatakan ini lebih merupakan keanehan daripada fitur nyata. Ini adalah penemuan yang keren.
toniedzwiedz
4
Benar ... tetap saja aku ingin melihat raut wajah rekan kerjaku ketika aku menunjukkan kepada mereka monster kecil yang lucu seperti ini jadi terima kasih lagi karena menunjukkan itu mungkin. Saya hanya pergi ke spesifikasi standar dan menyatakan itu hampir tidak mungkin, yang ternyata menjadi kesalahan (semacam)
toniedzwiedz
18
"Ketidakcocokan browser" di sini sebagian besar hanyalah kurangnya URL yang tepat untuk melarikan diri, semua yang ada di dalamnya url()harus di-url-escape. Lihat jsfiddle.net/6WAtQ untuk contoh yang berfungsi dengan baik di Opera, Firefox dan Safari.
Erik Dahlström
3
Apakah ada perbedaan kompatibilitas antara base64 yang dikodekan svg ke non-base64? Base64 menggembungkan file css saya, saya pikir hanya menggunakan svgs inline ..
enapupe
4
Catatan, cara standar untuk menentukan set karakter adalah dengan "; charset = UTF-8" alih-alih "; utf8". tools.ietf.org/html/rfc2397
Keith Shaw
240

Sedikit terlambat, tetapi jika ada di antara Anda yang sudah gila mencoba menggunakan inline SVG sebagai latar belakang , saran melarikan diri di atas tidak cukup berhasil. Untuk satu, itu tidak berfungsi di IE, dan tergantung pada konten SVG Anda teknik ini akan menyebabkan masalah di browser lain, seperti FF.

Jika Anda base64 mengkodekan svg (bukan seluruh url, hanya tag svg dan isinya!) Ia bekerja di semua browser. Berikut adalah contoh jsfiddle yang sama di base64: http://jsfiddle.net/vPA9z/3/

CSS sekarang terlihat seperti ini:

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

Ingatlah untuk menghapus URL yang keluar sebelum mengonversi ke base64. Dengan kata lain, contoh di atas menunjukkan color = '# fcc' dikonversi ke color = '% 23fcc', Anda harus kembali ke #.

Alasan mengapa base64 bekerja lebih baik adalah karena menghilangkan semua masalah dengan tanda kutip tunggal dan ganda serta url yang lolos

Jika Anda menggunakan JS, Anda dapat menggunakan window.btoa()untuk menghasilkan base64 svg Anda; dan jika itu tidak berhasil (mungkin mengeluh tentang karakter yang tidak valid dalam string), Anda cukup menggunakan https://www.base64encode.org/ .

Contoh untuk mengatur latar belakang 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>

Dengan JS, Anda dapat membuat SVG dengan cepat, bahkan mengubah parameternya.

Salah satu artikel yang lebih baik tentang penggunaan SVG ada di sini: http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

Semoga ini membantu

Mike

Mike Tommasi
sumber
2
Terima kasih sobat. Solusi dengan Base64 bekerja sangat baik, sementara saya mengalami masalah dengan jawaban yang diterima.
Marcel
1
Anda menyelamatkan hidup saya. Saya memiliki gambar perbatasan SVG yang berfungsi di chrome tetapi tidak pada FF. Sekarang berhasil! : D
Papipo
Membantu saya juga (setelah kehilangan waktu mencoba jawaban yang diterima) - ini pasti jawaban yang diterima.
Katai
Jika ini masih tidak bekerja untuk Anda - pastikan Anda memiliki xmlnsset atribut ke svgelemen sebelum Anda base64-encode seperti <svg xmlns="http://www.w3.org/2000/svg">...</svg>browser kadang-kadang memotong tanpa itu ketika svg langsung dalam HTML - ini BUKAN kasusnya :)
jave.web
Jika seseorang masih melihat jawaban ini 6+ tahun kemudian: Anda mungkin tidak seharusnya mendasarkan SVGs css-tricks.com/probably-dont-base64-svg
Volker E.
38

Untuk orang-orang yang masih berjuang, saya berhasil mendapatkan ini berfungsi di semua browser modern IE11 dan lebih tinggi.

base64 bukan pilihan bagi saya karena saya ingin menggunakan SASS untuk menghasilkan ikon SVG berdasarkan warna yang diberikan. Sebagai contoh: @include svg_icon(heart, #FF0000);Dengan cara ini saya dapat membuat ikon tertentu dalam warna apa pun, dan hanya perlu menyematkan bentuk SVG sekali dalam CSS. (dengan base64 Anda harus menanamkan SVG di setiap warna yang ingin Anda gunakan)

Ada tiga hal yang perlu Anda perhatikan:

  1. URL ENCODE SVG ANDA Seperti yang orang lain sarankan, Anda perlu URL menyandikan seluruh string SVG Anda agar dapat berfungsi di IE11. Dalam kasus saya, saya meninggalkan nilai warna di bidang seperti fill="#00FF00"dan stroke="#FF0000"dan menggantinya dengan variabel SASS fill="#{$color-rgb}"sehingga ini dapat diganti dengan warna yang saya inginkan. Anda dapat menggunakan konverter daring apa pun untuk menyandikan URL dari string. Anda akan berakhir dengan string SVG seperti ini:

    % 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% 20tinggi% 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% 20 isi% 3D% 27 # {$ color-rgb} % 27% 2F% 3C% 2Fsvg% 3E


  1. MENGHINDARI CHARSET UTF8 DALAM DATA URL Saat membuat URL data Anda, Anda perlu meninggalkan rangkaian karakter agar berfungsi di IE11.

    BUKAN gambar latar belakang: url (data: gambar / svg + xml; utf-8,% 3Csvg% 2 ....)
    TAPI gambar latar belakang: url (data: gambar / svg + xml,% 3Csvg% 2 ... .)


  1. GUNAKAN RGB () BUKAN warna HEX Firefox tidak suka # dalam kode SVG. Jadi, Anda perlu mengganti nilai hex warna Anda dengan yang RGB.

    JANGAN isi = "# FF0000"
    TAPI isi = "rgb (255,0,0)"

Dalam kasus saya, saya menggunakan SASS untuk mengkonversi hex yang diberikan ke nilai rgb yang valid. Seperti yang ditunjukkan dalam komentar, URL juga sebaiknya disandikan string RGB Anda (jadi koma menjadi% 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');
   }
}

Saya menyadari ini mungkin bukan solusi terbaik untuk SVG yang sangat kompleks (inline SVG tidak pernah ada dalam kasus itu), tetapi untuk ikon datar dengan hanya beberapa warna ini benar-benar berfungsi dengan baik.

Saya dapat meninggalkan seluruh bitmap sprite dan menggantinya dengan SVG inline di CSS saya, yang ternyata hanya sekitar 25kb setelah kompresi. Jadi ini cara yang bagus untuk membatasi jumlah permintaan yang harus dilakukan situs Anda, tanpa membengkak file CSS Anda.

Davy Baert
sumber
1
Btw, koreksi saya jika saya salah tetapi rgb(255,0,0)harus menjadi rgb(255%2C0%2C0)sekali dikodekan.
Kapsul
1
Maksud saya, saya tidak menyandikan string RGB dan masih berfungsi. Tetapi menyandikannya seperti yang Anda sebutkan mungkin lebih baik.
Davy Baert
1
Sebenarnya, saya baru saja menguji dan %23ff0000berfungsi dengan baik #ff0000di Firefox
Capsule
1
@Capsule Saya tidak tahu apa yang terjadi, tetapi% 23ff0000 adalah metode HANYA yang bekerja untuk saya di Chrome dan FF. # ff0000 tidak berfungsi, dan tidak juga metode RGB (255,0,0) dan rgb (255% 2C0% 2C0).
Ideogram
1
Sebuah metode (termasuk kode SCSS) yang memerlukan lebih sedikit pengkodean: codepen.io/jakob-e/pen/doMoML
Sphinxxx
26

Di Mac / Linux, Anda dapat dengan mudah mengonversi file SVG ke nilai yang disandikan base64 untuk atribut latar belakang CSS dengan perintah bash sederhana ini:

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

Diuji pada Mac OS X. Dengan cara ini Anda juga menghindari URL yang keluar dari kekacauan.

Ingat bahwa base64 yang menyandikan file SVG memperbesar ukurannya, lihat posting blog css-tricks.com .

araks
sumber
2
Kepada para pembaca: tolong komentari pendapat Anda alih-alih hanya memilih, jadi jawaban ini dapat ditingkatkan dengan kolaborasi Anda! Kolaborasi sangat penting dalam situs tanya jawab seperti ini. Terima kasih!
araks
2
@LorDex tautan yang Anda berikan dalam komentar Anda sama dengan jawaban saya :)
araks
10

Saya telah melakukan forked demo CodePen yang memiliki masalah yang sama dengan menanamkan SVG inline ke dalam CSS. Solusi yang bekerja dengan SCSS adalah membangun fungsi penyandian url sederhana.

Fungsi penggantian string dapat dibuat dari fungsi str-slice, str-index yang terintegrasi (lihat trik-trik css , terima kasih kepada Hugo Giraudel).

Kemudian, hanya mengganti %, <, >, ", ', dengan %xxkode:

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

Ada juga image-inlinefungsi pembantu yang tersedia di Compass, tetapi karena tidak didukung di CodePen, solusi ini mungkin berguna.

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

Lea Rosema
sumber
1
Saya juga membuat pena yang memungkinkan Anda untuk mengubah string svg menjadi nilai latar belakang css yang tepat: s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb Jadi, pada dasarnya, Anda menempelkan Anda <svg><path></svg>ke textarea teratas, dan itu akan langsung mengeluarkan jalur saniter yang sudah dibersihkan. dalam suatu url()nilai.
LukyVj
1
Ini berhasil luar biasa. Terima kasih. Satu catatan. Anda perlu menggunakan; charset = utf8 untuk mendapatkan ini berfungsi di IE.
Daniel Lefebvre
4

SVG sebaris yang berasal dari sumber pihak ketiga (seperti bagan Google) mungkin tidak mengandung atribut namespace XML ( xmlns="http://www.w3.org/2000/svg") dalam elemen SVG (atau mungkin dihapus ketika SVG di-render - baik browser inspektur maupun perintah jQuery dari konsol browser menunjukkan namespace dalam elemen SVG).

Saat Anda perlu mengarahkan ulang cuplikan svg ini untuk kebutuhan Anda yang lain (background-image dalam CSS atau elemen img dalam HTML) hati-hati terhadap namespace yang hilang. Tanpa namespace browser dapat menolak untuk menampilkan SVG (terlepas dari utf8 atau encoding base64).

mp31415
sumber
4

Saya menemukan satu solusi untuk SVG. Tapi ini hanya berfungsi untuk Webkit, saya hanya ingin berbagi solusi dengan Anda. Dalam contoh saya ditunjukkan bagaimana menggunakan elemen SVG dari DOM sebagai latar belakang melalui filter (background-image: url ('# glyph') tidak berfungsi).

Fitur yang diperlukan untuk render ikon SVG ini:

  1. Menerapkan efek filter SVG ke elemen HTML menggunakan CSS (IE dan Edge tidak mendukung)
  2. pendukung beban fragmen feImage (firefox tidak mendukung)

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

Satu lagi solusi, gunakan url encode

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
sumber