Nội tuyến SVG trong CSS


283

Có thể sử dụng định nghĩa SVG nội tuyến trong CSS không?

Ý tôi là đại loại như:

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

1
Bạn đang cố gắng làm gì, thêm "nguồn" hình ảnh vào biểu định kiểu?
Zuul

1
Coi chừng các giải pháp được đề xuất sẽ không hoạt động đối với hình ảnh CSS, <img>thẻ HTML và các trường hợp khác nếu SVG là hỗn hợp của một số hình ảnh (trừ khi được nhúng), xem hình nền SVG với mặt nạ sử dụng hình ảnh bên ngoài không hoạt động và cụ thể hạn chế sử dụng SVG như một hình ảnh .
Skippy le Grand Gourou

Câu trả lời:


374

Vâng, nó là có thể. Thử cái này:

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

(Lưu ý rằng nội dung SVG cần được thoát url để làm việc này, ví dụ: #được thay thế bằng %23.)

Điều này hoạt động trong IE 9 (hỗ trợ SVG) . URL dữ liệu cũng hoạt động trong các phiên bản IE cũ hơn (có giới hạn), nhưng chúng không hỗ trợ SVG.


8
Trình duyệt duy nhất có vẻ hoạt động độc đáo là Safari (5.1.4). Trong Opera 11.62, gradient có màu đen, trong IE 9 và Firefox 12 có màu trắng. Trong Chrome 19, nó hoạt động KHÔNG GIỚI HẠN bạn chỉ định chiều rộng / chiều cao của SVG theo% đơn vị. Tôi muốn nói nó kỳ quặc hơn là một tính năng thực sự. Đó là một phát hiện tuyệt vời mặc dù.
toniedzwiedz

4
Phải ... tôi vẫn lo lắng khi thấy vẻ mặt của đồng nghiệp khi tôi cho họ thấy một con quái vật nhỏ dễ thương như thế này, cảm ơn lần nữa vì đã cho thấy điều đó là có thể. Tôi vừa đi đến đặc điểm kỹ thuật tiêu chuẩn và nói rằng nó hầu như không thể, hóa ra đó là một sai lầm (loại)
toniedzwiedz

18
"Không tương thích trình duyệt" ở đây chủ yếu chỉ là thiếu URL thoát thích hợp, mọi thứ bên trong url()phải được thoát url. Xem jsfiddle.net/6WAtQ để biết ví dụ hoạt động tốt trong Opera, Firefox và Safari.
Erik Dahlström

3
Có sự khác biệt nào về khả năng tương thích giữa svg được mã hóa base64 với non-base64 không? Base64 làm mờ tập tin css của tôi, tôi đang nghĩ chỉ cần sử dụng các nội dung trực tuyến ..
enapupe

4
Lưu ý, cách tiêu chuẩn để chỉ định bộ ký tự là với "; charset = UTF-8" thay vì "; utf8". tools.ietf.org/html/rfc2394
Keith Shaw

240

Hơi muộn một chút, nhưng nếu bất kỳ ai trong số các bạn đang phát điên khi cố gắng sử dụng SVG nội tuyến làm nền , thì các đề xuất thoát ở trên không hoàn toàn hiệu quả. Đối với một, nó không hoạt động trong IE và tùy thuộc vào nội dung của SVG của bạn, kỹ thuật sẽ gây rắc rối trong các trình duyệt khác, như FF.

Nếu bạn base64 mã hóa svg (không phải toàn bộ url, chỉ cần thẻ svg và nội dung của nó!) Thì nó hoạt động trong tất cả các trình duyệt. Dưới đây là ví dụ jsfiddle tương tự trong cơ sở64: http://jsfiddle.net/vPA9z/3/

CSS bây giờ trông như thế này:

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

Hãy nhớ xóa bất kỳ URL nào thoát trước khi chuyển đổi sang base64. Nói cách khác, ví dụ trên cho thấy color = '# fcc' được chuyển đổi thành color = '% 23fcc', bạn nên quay lại #.

Lý do tại sao base64 hoạt động tốt hơn là vì nó loại bỏ tất cả các vấn đề với dấu ngoặc đơn và dấu ngoặc kép và thoát url

Nếu bạn đang sử dụng JS, bạn có thể sử dụng window.btoa()để tạo cơ sở64 svg; và nếu nó không hoạt động (nó có thể phàn nàn về các ký tự không hợp lệ trong chuỗi), bạn chỉ cần sử dụng https://www.base64encode.org/ .

Ví dụ để đặt nền 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>

Với JS, bạn có thể tạo các SVG một cách nhanh chóng, thậm chí thay đổi các tham số của nó.

Một trong những bài viết tốt hơn về việc sử dụng SVG có tại đây: http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

Hi vọng điêu nay co ich

Mike


2
Cảm ơn, anh bạn. Giải pháp với Base64 hoạt động rất tốt, trong khi tôi gặp rắc rối với câu trả lời được chấp nhận.
Marcel

1
Bạn đã cứu cuộc đời tôi. Tôi đã có một hình ảnh viền SVG đang hoạt động trong chrome nhưng không phải trên FF. Bây giờ nó hoạt động! : D
Papipo

Cũng giúp tôi (sau khi mất thời gian thử câu trả lời được chấp nhận) - đây chắc chắn sẽ là câu trả lời được chấp nhận.
Katai

Nếu điều này vẫn không hiệu quả với bạn - hãy đảm bảo rằng bạn đã xmlnsđặt thuộc tính thành svgphần tử trước khi bạn mã hóa cơ sở như <svg xmlns="http://www.w3.org/2000/svg">...</svg>trình duyệt đôi khi chunk nó mà không có nó khi svg trực tiếp trong HTML - đây không phải là trường hợp :)
jave.web

Trong trường hợp ai đó vẫn đang xem câu trả lời này hơn 6 năm sau: Có lẽ bạn không nên căn cứ64 SVGs css-tricks.com/probossible-dont-base64-svg
Volker E.

38

Đối với những người vẫn đang gặp khó khăn, tôi đã quản lý để làm việc này trên tất cả các trình duyệt hiện đại IE11 trở lên.

Base64 không phải là lựa chọn cho tôi vì tôi muốn sử dụng SASS để tạo các biểu tượng SVG dựa trên bất kỳ màu nào. Ví dụ: @include svg_icon(heart, #FF0000);Bằng cách này, tôi có thể tạo một biểu tượng nhất định bằng bất kỳ màu nào và chỉ phải nhúng hình dạng SVG một lần trong CSS. (với Base64, bạn phải nhúng SVG vào từng màu bạn muốn sử dụng)

Có ba điều bạn cần lưu ý:

  1. URL ENCODE SVG CỦA BẠN Như những người khác đã đề xuất, bạn cần URL mã hóa toàn bộ chuỗi SVG của bạn để nó hoạt động trong IE11. Trong trường hợp của tôi, tôi bỏ qua các giá trị màu sắc trong các lĩnh vực như fill="#00FF00"stroke="#FF0000"và thay thế chúng bằng một biến Sass fill="#{$color-rgb}"nên chúng có thể được thay thế bằng màu sắc tôi muốn. Bạn có thể sử dụng bất kỳ trình chuyển đổi trực tuyến nào để URL mã hóa phần còn lại của chuỗi. Bạn sẽ kết thúc với một chuỗi SVG như thế này:

    % 3Csvg% 20xmlns% 3D% 27http% 3A% 2F% 2Fwww.w3.org% 2F2000% 2Fsvg% 27% 20viewBox% 3D% 270% 200% 20494.572% 20494.572% 27% 20 %% 3D% 27512% % 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% % 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% 3 %% 3E


  1. OMIT CHARSET UTF8 TRONG URL DATA Khi tạo URL dữ liệu của bạn, bạn cần bỏ qua bộ ký tự để nó hoạt động trong IE11.

    KHÔNG phải hình nền: url (dữ liệu: hình ảnh / svg + xml; utf-8,% 3Csvg% 2 ....)
    NHƯNG hình nền: url (dữ liệu: hình ảnh / svg + xml,% 3Csvg% 2 ... .)


  1. SỬ DỤNG RGB () INSTEAD OF HEX màu Firefox không thích # trong mã SVG. Vì vậy, bạn cần thay thế các giá trị hex màu của bạn bằng các giá trị RGB.

    KHÔNG điền = "# FF0000"
    NHƯNG điền = "rgb (255,0,0)"

Trong trường hợp của tôi, tôi sử dụng SASS để chuyển đổi một hex đã cho thành giá trị rgb hợp lệ. Như đã chỉ ra trong các nhận xét, tốt nhất là URL cũng mã hóa chuỗi RGB của bạn (vì vậy dấu phẩy trở thành% 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');
   }
}

Tôi nhận ra rằng đây có thể không phải là giải pháp tốt nhất cho các SVG rất phức tạp (SVG nội tuyến không bao giờ có trong trường hợp đó), nhưng đối với các biểu tượng phẳng chỉ có một vài màu thì điều này thực sự hiệu quả.

Tôi đã có thể loại bỏ toàn bộ bitmap sprite và thay thế nó bằng SVG nội tuyến trong CSS của mình, hóa ra chỉ còn khoảng 25kb sau khi nén. Vì vậy, đó là một cách tuyệt vời để giới hạn số lượng yêu cầu mà trang web của bạn phải thực hiện mà không làm đầy tệp CSS của bạn.


1
Btw, sửa tôi nếu tôi sai nhưng rgb(255,0,0)sẽ rgb(255%2C0%2C0)được mã hóa một lần.
Viên nang

1
Ý tôi là tôi không mã hóa chuỗi RGB và nó vẫn hoạt động. Nhưng mã hóa nó như bạn đã đề cập có lẽ tốt hơn.
Davy Baert

1
Chà, thực ra, tôi vừa thử nghiệm và %23ff0000hoạt động tốt #ff0000trong Firefox
Capsule

1
@Capsule Tôi không biết chuyện gì đang xảy ra, nhưng% 23ff0000 là phương pháp DUY NHẤT phù hợp với tôi trên cả Chrome và FF. # ff0000 không hoạt động và cũng không thực hiện các phương thức RGB (255,0,0) và rgb (255% 2C0% 2C0).
Ideogram

1
Một phương thức (bao gồm mã SCSS) yêu cầu mã hóa ít hơn: codepen.io/jakob-e/pen/doMoML
Sphinxxx

26

Trên Mac / Linux, bạn có thể dễ dàng chuyển đổi tệp SVG thành giá trị được mã hóa base64 cho thuộc tính nền CSS bằng lệnh bash đơn giản này:

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

Đã thử nghiệm trên Mac OS X. Bằng cách này, bạn cũng tránh được tình trạng thoát URL lộn xộn.

Hãy nhớ rằng base64 mã hóa một tệp SVG tăng kích thước của nó, xem bài đăng trên blog của css-tricks.com .


2
Đối với độc giả: vui lòng bình luận ý kiến ​​của bạn thay vì chỉ bỏ phiếu, vì vậy câu trả lời này có thể được cải thiện với sự cộng tác của bạn! Hợp tác là điều cần thiết trong các trang web hỏi đáp như thế này. Cảm ơn bạn!
trả lời

2
@LorDex liên kết bạn cung cấp trong nhận xét của bạn giống với câu trả lời của tôi :)
araks

10

Tôi đã rẽ nhánh một bản demo CodePen có cùng vấn đề với việc nhúng SVG nội tuyến vào CSS. Một giải pháp hoạt động với SCSS là xây dựng chức năng mã hóa url đơn giản.

Một hàm thay thế chuỗi có thể được tạo từ các hàm str-lát, str-index tích hợp (xem css-trick , nhờ Hugo Giraudel).

Sau đó, chỉ cần thay thế %, <, >, ", ', với các %xxmã:

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

Ngoài ra còn có một image-inlinechức năng trợ giúp có sẵn trong La bàn, nhưng vì nó không được hỗ trợ trong CodePen, giải pháp này có thể hữu ích.

Bản trình diễn trên CodePen: http://codepen.io/terabaud/details/PZdaJo/


1
Tôi cũng đã tạo ra một cây bút cho phép bạn chuyển đổi các chuỗi svg thành giá trị nền css thích hợp: s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb Vì vậy, về cơ bản, bạn sẽ dán <svg><path></svg>trực tiếp vào đường dẫn trong một url()giá trị
LukyVj

1
Điều này làm việc tuyệt vời. Cảm ơn bạn. Một lưu ý. Bạn cần sử dụng; charset = utf8 để làm việc này trong IE.
Daniel Lefebvre

4

SVG nội tuyến đến từ các nguồn của bên thứ 3 (như biểu đồ Google) có thể không chứa thuộc tính không gian tên XML ( xmlns="http://www.w3.org/2000/svg") trong phần tử SVG (hoặc có thể bị xóa sau khi SVG được hiển thị - không phải trình kiểm tra trình duyệt cũng như lệnh jQuery từ bảng điều khiển trình duyệt hiển thị không gian tên trong phần tử SVG).

Khi bạn cần tái mục đích các đoạn mã Svg này cho các nhu cầu khác của bạn (hình nền trong phần tử CSS hoặc img trong HTML), hãy coi chừng không gian tên bị thiếu. Nếu không có các trình duyệt không gian tên có thể từ chối hiển thị SVG (bất kể mã hóa utf8 hoặc base64).


4

Tôi tìm thấy một giải pháp cho SVG. Nhưng nó chỉ hoạt động cho Webkit, tôi chỉ muốn chia sẻ cách giải quyết của tôi với bạn. Trong ví dụ của tôi được chỉ ra cách sử dụng phần tử SVG từ DOM làm nền thông qua bộ lọc (hình nền: url ('# glyph') không hoạt động).

Các tính năng cần thiết cho biểu tượng SVG này kết xuất:

  1. Áp dụng hiệu ứng bộ lọc SVG cho các phần tử HTML bằng CSS (không hỗ trợ IE và Edge)
  2. hỗ trợ tải mảnh vỡ hình ảnh (firefox không hỗ trợ)

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

Một giải pháp nữa là sử dụng mã hóa 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>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.