Sửa đổi màu tô SVG khi được dùng làm Ảnh nền


270

Đặt đầu ra SVG trực tiếp nội tuyến với mã trang Tôi có thể chỉ cần sửa đổi màu tô bằng CSS như vậy:

polygon.mystar {
    fill: blue;
}​

circle.mycircle {
    fill: green;
}

Điều này hoạt động rất tốt, tuy nhiên tôi đang tìm cách sửa đổi thuộc tính "điền" của một SVG khi nó được phục vụ dưới dạng BACKGROUND-IMAGE.

html {      
    background-image: url(../img/bg.svg);
}

Làm thế nào tôi có thể thay đổi màu sắc bây giờ? Nó thậm chí có thể?

Để tham khảo, đây là nội dung của tệp SVG bên ngoài của tôi:

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="320px" height="100px" viewBox="0 0 320 100" enable-background="new 0 0 320 100" xml:space="preserve">
<polygon class="mystar" fill="#3CB54A" points="134.973,14.204 143.295,31.066 161.903,33.77 148.438,46.896 151.617,65.43 134.973,56.679 
    118.329,65.43 121.507,46.896 108.042,33.77 126.65,31.066 "/>
<circle class="mycircle" fill="#ED1F24" cx="202.028" cy="58.342" r="12.26"/>
</svg>

Tôi bị đánh thường xuyên với đạo cụ cho câu trả lời của tôi. Bạn nên xem xét thay đổi nó thành câu trả lời được chấp nhận để nó không bị bỏ lỡ.
Ryan

Câu trả lời:


75

Một cách để làm điều này là phục vụ svg của bạn từ một số cơ chế phía máy chủ. Chỉ cần tạo một phía máy chủ tài nguyên xuất ra Svg của bạn theo các tham số GET và bạn phục vụ nó trên một url nhất định.

Sau đó, bạn chỉ cần sử dụng url đó trong css của bạn.

Bởi vì làm nền img, nó không phải là một phần của DOM và bạn không thể thao tác nó. Một khả năng khác là sử dụng nó thường xuyên, nhúng nó vào một trang theo cách thông thường, nhưng định vị nó một cách tuyệt đối, làm cho nó có chiều rộng và chiều cao đầy đủ của trang và sau đó sử dụng thuộc tính css z-index để đặt nó phía sau tất cả các thành phần DOM khác trên một trang


7
Đừng quên nếu bạn đang phục vụ SVG từ tập lệnh phía máy chủ, để đảm bảo bạn cũng gửi tiêu đề MIME chính xác . Trong PHP, điều này sẽ là:<?php header('Content-type: image/svg+xml'); ?>
Saul Fautley

4
Bạn có thể sử dụng hình ảnh svg làm mặt nạ và thao tác màu nền của phần tử. Điều này sẽ có tác dụng tương tự như thay đổi điền. (câu trả lời chi tiết được cung cấp)
mở rộng

16
Câu trả lời này rất hay vào năm 2012, nhưng hiện tại mặt nạ và / hoặc bộ lọc CSS đã được hỗ trợ trong tất cả các trình duyệt. Tôi khuyên mọi người nên đọc ngay bây giờ, hãy kiểm tra các liên kết trong câu trả lời mở rộng bên dưới hoặc bỏ qua CSS Masks ở đây , đây là một giải pháp thực sự dễ dàng - lưu ý rằng nó vẫn yêu cầu 2 phiên bản quy tắc, một phiên bản có tiền tố -webkit- hiện tại thời gian. Đối với Microsoft Edge, các bộ lọc CSS hiện được hỗ trợ nhưng chưa có mặt nạ.
joelhardi

2
Có nhiều giải pháp cung cấp dưới đây hoạt động hiện nay, tôi đồng ý câu trả lời này không còn phản ánh tình trạng khả năng hiện tại.
David Neto

148

Tôi cần một cái gì đó tương tự và muốn gắn bó với CSS. Dưới đây là các mixin LESS và SCSS cũng như CSS đơn giản có thể giúp bạn điều này. Thật không may, hỗ trợ trình duyệt của nó là một chút lỏng lẻo. Xem bên dưới để biết chi tiết về hỗ trợ trình duyệt.

LESS mixin:

.element-color(@color) {
  background-image: url('data:image/svg+xml;utf8,<svg ...><g stroke="@{color}" ... /></g></svg>');
}

Sử dụng LESS:

.element-color(#fff);

Hỗn hợp SCSS:

@mixin element-color($color) {
  background-image: url('data:image/svg+xml;utf8,<svg ...><g stroke="#{$color}" ... /></g></svg>');
}

Sử dụng SCSS:

@include element-color(#fff);

CSS:

// color: red
background-image: url('data:image/svg+xml;utf8,<svg ...><g stroke="red" ... /></g></svg>');

Dưới đây là thông tin thêm về việc nhúng mã SVG đầy đủ vào tệp CSS của bạn. Nó cũng đề cập đến khả năng tương thích trình duyệt, một chút quá nhỏ để đây là một lựa chọn khả thi.


Mặc dù có một chút chi phí, vì tôi phải mã hóa tất cả các mục của Svg, tôi nghĩ rằng đây là giải pháp tốt nhất trong một thời gian. Cảm ơn
Adriano Rosa

Bạn cần sử dụng bộ tiền xử lý CSS như Sass hoặc Less nếu bạn muốn sử dụng theo cách này. Nếu bạn không sử dụng một, bạn sẽ chỉ cần sử dụng dòng hình nền đó cho mỗi màu
Mã thân thiện

36
Lưu ý rằng bạn phải urlencode #ký tự cho các màu hex của bạn để làm cho điều này hoạt động trong Firefox. Vì vậy, một cái gì đó như <svg fill="#ffffff" ...></svg>trở thành <svg fill="%23ffffff" ...></svg>.
Swen

1
Phương pháp ngọt ngào. Bạn có phải khó mã hóa các Svg vào hình nền như thế không? Bạn có thể không chỉ liên kết với nó bằng cách nào đó?
luke

2
Tôi thấy trang web này hữu ích để cung cấp cho bạn URL được mã hóa hoàn hảo sẵn sàng để sử dụng: yoksel.github.io/url-encoder - Chỉ cần sao chép mã SVG vào đó và sao chép CSS trả về :-)
Mã thân thiện

95

Bạn có thể sử dụng mặt nạ CSS, Với thuộc tính 'mặt nạ', bạn tạo mặt nạ được áp dụng cho một phần tử.

.icon {
    background-color: red;
    -webkit-mask-image: url(icon.svg);
    mask-image: url(icon.svg);
}

Để biết thêm xem bài viết tuyệt vời này: https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images


3
điều này là tốt nhưng khi được áp dụng cho một biểu tượng trong trường đầu vào, tất cả văn bản đầu vào bị ẩn đi.
raison

14
Không được hỗ trợ trong IE
Kareem

Câu trả lời cực hay, nhưng bạn không còn có thể sử dụng màu nền trong di chuột hoặc thứ gì đó tương tự
Paul Kruger

Điều này dường như hầu như không được hỗ trợ nếu tất cả - quá nhiều người dùng sẽ không thể thấy điều này khả thi vào ngày hôm nay vào cuối năm 2018. caniuse.com/#feat=css-masks
Chris Moschini

3
Mùa hè 2019: 94% trình duyệt trên hành tinh này hỗ trợ kiểu "mask-image" HOẶC "-webkit-mask-image"
Dmitry Kulahin

57

Một cách tiếp cận khác là sử dụng mặt nạ. Sau đó, bạn thay đổi màu nền của thành phần đeo mặt nạ. Điều này có tác dụng tương tự như thay đổi thuộc tính điền của svg.

HTML:

<glyph class="star"/>
<glyph class="heart" />
<glyph class="heart" style="background-color: green"/>
<glyph class="heart" style="background-color: blue"/>

CSS:

glyph {
    display: inline-block;
    width:  24px;
    height: 24px;
}

glyph.star {
  -webkit-mask: url(star.svg) no-repeat 100% 100%;
  mask: url(star.svg) no-repeat 100% 100%;
  -webkit-mask-size: cover;
  mask-size: cover;
  background-color: yellow;
}

glyph.heart {
  -webkit-mask: url(heart.svg) no-repeat 100% 100%;
  mask: url(heart.svg) no-repeat 100% 100%;
  -webkit-mask-size: cover;
  mask-size: cover;
  background-color: red;
}

Bạn sẽ tìm thấy một hướng dẫn đầy đủ ở đây: http://codepen.io/noahblon/blog/coloring-svgs-in-css-background-images (không phải của riêng tôi). Nó đề xuất một loạt các phương pháp tiếp cận (không giới hạn ở mặt nạ).


11
Một điều cần lưu ý về điều này là hỗ trợ trình duyệt. Tôi tin rằng IE (như thường lệ) là cách phía sau về điều này.
Matthew Johnson

9
Thật không may, maskkhông được IE và Edge hỗ trợ: caniuse.com/#search=mask
alpipego 30/03/2016

Không hoạt động với tôi trong Chrome. Chỉnh sửa: Oh nvm ... Tôi không kích hoạt autoprefixer. Tôi nghĩ các nhà cung cấp đáng lẽ phải ngừng sử dụng tiền tố?!
mở

Hoạt động trong chrome và firefox mới nhất
tic

16

Điều đó là có thể với Sass! Điều duy nhất bạn phải làm là mã hóa url mã Svg của bạn. Và điều này là có thể với chức năng trợ giúp trong Sass. Tôi đã tạo một codepen cho việc này. Nhìn vào cái này

http://codepen.io/philippkuehn/pen/zGEjxB

// choose a color

$icon-color: #F84830;


// functions to urlencode the svg string

@function str-replace($string, $search, $replace: '') {
  $index: str-index($string, $search);
  @if $index {
    @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
  }
  @return $string;
}

@function url-encode($string) {
  $map: (
    "%": "%25",
    "<": "%3C",
    ">": "%3E",
    " ": "%20",
    "!": "%21",
    "*": "%2A",
    "'": "%27",
    '"': "%22",
    "(": "%28",
    ")": "%29",
    ";": "%3B",
    ":": "%3A",
    "@": "%40",
    "&": "%26",
    "=": "%3D",
    "+": "%2B",
    "$": "%24",
    ",": "%2C",
    "/": "%2F",
    "?": "%3F",
    "#": "%23",
    "[": "%5B",
    "]": "%5D"
  );
  $new: $string;
  @each $search, $replace in $map {
    $new: str-replace($new, $search, $replace);
  }
  @return $new;
}

@function inline-svg($string) {
  @return url('data:image/svg+xml;utf8,#{url-encode($string)}');
}


// icon styles
// note the fill="' + $icon-color + '"

.icon {
  display: inline-block;
  width: 50px;
  height: 50px;
  background: inline-svg('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
   viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve">
<path fill="' + $icon-color + '" d="M18.7,10.1c-0.6,0.7-1,1.6-0.9,2.6c0,0.7-0.6,0.8-0.9,0.3c-1.1-2.1-0.4-5.1,0.7-7.2c0.2-0.4,0-0.8-0.5-0.7
  c-5.8,0.8-9,6.4-6.4,12c0.1,0.3-0.2,0.6-0.5,0.5c-0.6-0.3-1.1-0.7-1.6-1.3c-0.2-0.3-0.4-0.5-0.6-0.8c-0.2-0.4-0.7-0.3-0.8,0.3
  c-0.5,2.5,0.3,5.3,2.1,7.1c4.4,4.5,13.9,1.7,13.4-5.1c-0.2-2.9-3.2-4.2-3.3-7.1C19.6,10,19.1,9.6,18.7,10.1z"/>
</svg>');
}

2
Điều này làm việc rất tốt. Vấn đề duy nhất: Trong IE10, biểu tượng quá nhỏ (tôi nghĩ 10% kích thước đã cho.
Henning Fischer

13
 .icon { 
  width: 48px;
  height: 48px;
  display: inline-block;
  background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/18515/heart.svg) no-repeat 50% 50%; 
  background-size: cover;
}

.icon-orange { 
  -webkit-filter: hue-rotate(40deg) saturate(0.5) brightness(390%) saturate(4); 
  filter: hue-rotate(40deg) saturate(0.5) brightness(390%) saturate(4); 
}

.icon-yellow {
  -webkit-filter: hue-rotate(70deg) saturate(100);
  filter: hue-rotate(70deg) saturate(100);
}

bài viết và bản demo của codeben


1
Phương pháp này sẽ áp dụng bộ lọc cho toàn bộ đối tượng, bao gồm cả trẻ em.
Krzysztof Antoniak

9

Tải về Svg của bạn dưới dạng văn bản.

Sửa đổi văn bản svg của bạn bằng cách sử dụng javascript để thay đổi màu vẽ / nét / tô màu [s].

Sau đó nhúng chuỗi nội dung svg đã sửa đổi vào css của bạn như được mô tả ở đây .


9

Bây giờ bạn có thể đạt được điều này ở phía khách hàng như thế này:

var green = '3CB54A';
var red = 'ED1F24';
var svg = '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"  width="320px" height="100px" viewBox="0 0 320 100" enable-background="new 0 0 320 100" xml:space="preserve"> <polygon class="mystar" fill="#'+green+'" points="134.973,14.204 143.295,31.066 161.903,33.77 148.438,46.896 151.617,65.43 134.973,56.679 118.329,65.43 121.507,46.896 108.042,33.77 126.65,31.066 "/><circle class="mycircle" fill="#'+red+'" cx="202.028" cy="58.342" r="12.26"/></svg>';      
var encoded = window.btoa(svg);
document.body.style.background = "url(data:image/svg+xml;base64,"+encoded+")";

Fiddle ở đây!


1
Bạn nên tránh sử dụng Base64 cho SVG vì nó không cần thiết, làm cho các tệp của bạn lớn hơn và thậm chí ngăn GZIP nén hiệu quả các đoạn mã đó.
inta

1
Mã hóa này đang xảy ra ở phía khách hàng, có lẽ chỉ để thoát triệt để ...
diachedelic

Không cần phải nói bạn có thể làm bất cứ điều gì với JS. Vấn đề là tránh JS.
MarsAndBack

7

Bạn có thể lưu trữ SVG trong một biến. Sau đó, thao tác chuỗi SVG tùy thuộc vào nhu cầu của bạn (nghĩa là đặt chiều rộng, chiều cao, màu sắc, v.v.). Sau đó sử dụng kết quả để đặt nền, vd

$circle-icon-svg: '<svg xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="10" r="10" /></svg>';

$icon-color: #f00;
$icon-color-hover: #00f;

@function str-replace($string, $search, $replace: '') {
    $index: str-index($string, $search);

    @if $index {
        @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
    }

    @return $string;
}

@function svg-fill ($svg, $color) {
  @return str-replace($svg, '<svg', '<svg fill="#{$color}"');
}

@function svg-size ($svg, $width, $height) {
  $svg: str-replace($svg, '<svg', '<svg width="#{$width}"');
  $svg: str-replace($svg, '<svg', '<svg height="#{$height}"');

  @return $svg;
}

.icon {
  $icon-svg: svg-size($circle-icon-svg, 20, 20);

  width: 20px; height: 20px; background: url('data:image/svg+xml;utf8,#{svg-fill($icon-svg, $icon-color)}');

  &:hover {
    background: url('data:image/svg+xml;utf8,#{svg-fill($icon-svg, $icon-color-hover)}');
  }
}

Tôi cũng đã làm một bản demo, http://sassmeister.com/gist/4cf0265c5d0143a9e734 .

Mã này đưa ra một vài giả định về SVG, ví dụ: <svg /> phần tử đó không có màu tô hiện có và không có thuộc tính chiều rộng hoặc chiều cao nào được đặt. Do đầu vào được mã hóa cứng trong tài liệu SCSS, nên việc thực thi các ràng buộc này là khá dễ dàng.

Đừng lo lắng về việc sao chép mã. nén làm cho sự khác biệt không đáng kể.


Mã trùng lặp là một mùi mã, vì vậy, đề nghị mọi người không nên lo lắng về mã trùng lặp trong trường hợp ví dụ của bạn không phải là một ý tưởng hay, tuy nhiên điều đó nói rằng tôi không thể thấy mã của bạn bị trùng lặp ở đâu? Tôi nghĩ rằng nó sẽ đọc tốt hơn nếu bạn hoàn toàn xóa bình luận.
Giáo sư lập trình

3

Bạn có thể tạo chức năng SCSS của riêng bạn cho việc này. Thêm phần sau vào tập tin config.rb của bạn.

require 'sass'
require 'cgi'

module Sass::Script::Functions

  def inline_svg_image(path, fill)
    real_path = File.join(Compass.configuration.images_path, path.value)
    svg = data(real_path)
    svg.gsub! '{color}', fill.value
    encoded_svg = CGI::escape(svg).gsub('+', '%20')
    data_url = "url('data:image/svg+xml;charset=utf-8," + encoded_svg + "')"
    Sass::Script::String.new(data_url)
  end

private

  def data(real_path)
    if File.readable?(real_path)
      File.open(real_path, "rb") {|io| io.read}
    else
      raise Compass::Error, "File not found or cannot be read: #{real_path}"
    end
  end

end

Sau đó, bạn có thể sử dụng nó trong CSS của bạn:

.icon {
  background-image: inline-svg-image('icons/icon.svg', '#555');
}

Bạn sẽ cần chỉnh sửa các tệp SVG của mình và thay thế bất kỳ thuộc tính điền nào trong đánh dấu bằng fill = "{color}"

Đường dẫn biểu tượng luôn liên quan đến tham số hình ảnh của bạn trong cùng tệp config.rb.

Tương tự như một số giải pháp khác, nhưng điều này khá sạch sẽ và giữ cho các tệp SCSS của bạn gọn gàng!


1
đây là từ một vấn đề github . Chỉ cần tham khảo nó ở đây trong trường hợp ai đó muốn đọc cuộc thảo luận ở đó
MMachinegun

2

Trong một số tình huống (rất cụ thể) điều này có thể đạt được bằng cách sử dụng bộ lọc . Ví dụ: bạn có thể thay đổi hình ảnh SVG màu xanh thành màu tím bằng cách xoay màu sắc 45 độ bằng cách sử dụngfilter: hue-rotate(45deg); . Hỗ trợ trình duyệt là tối thiểu nhưng nó vẫn là một kỹ thuật thú vị.

Bản giới thiệu


2

đối với nền đơn sắc, bạn có thể sử dụng một Svg với mặt nạ, trong đó màu nền sẽ được hiển thị

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" preserveAspectRatio="xMidYMid meet" focusable="false" style="pointer-events: none; display: block; width: 100%; height: 100%;" >
    <defs>
        <mask id="Mask">
            <rect width="100%" height="100%" fill="#fff" />
            <polyline stroke-width="2.5" stroke="black" stroke-linecap="square" fill="none" transform="translate(10.373882, 8.762969) rotate(-315.000000) translate(-10.373882, -8.762969) " points="7.99893906 13.9878427 12.7488243 13.9878427 12.7488243 3.53809523"></polyline>
        </mask>
    </defs>
    <rect x="0" y="0" width="20" height="20" fill="white" mask="url(#Mask)" />
</svg>

và hơn là sử dụng css này

background-repeat: no-repeat;
background-position: center center;
background-size: contain;
background-image: url(your/path/to.svg);
background-color: var(--color);


1

Đến cuối chương trình ở đây, NHƯNG, tôi đã có thể thêm màu tô vào đa giác SVG, nếu bạn có thể chỉnh sửa trực tiếp mã SVG, vì vậy, ví dụ như Svg sau sẽ chuyển sang màu đỏ, thay vì màu đen mặc định. Tôi chưa thử nghiệm bên ngoài Chrome:

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
    <polygon 


        fill="red"


        fill-rule="evenodd" clip-rule="evenodd" points="452.5,233.85 452.5,264.55 110.15,264.2 250.05,390.3 229.3,413.35 
47.5,250.7 229.3,86.7 250.05,109.75 112.5,233.5 "/>
</svg>

-2

Đây là phương pháp yêu thích của tôi, nhưng hỗ trợ trình duyệt của bạn phải rất tiến bộ. Với thuộc tính mặt nạ, bạn tạo một mặt nạ được áp dụng cho một phần tử. Ở mọi nơi mặt nạ mờ đục, hoặc rắn, hình ảnh bên dưới hiển thị thông qua. Trong trường hợp trong suốt, hình ảnh bên dưới bị che khuất hoặc ẩn đi. Cú pháp cho hình ảnh mặt nạ CSS tương tự như hình nền. nhìn vào codepenmask


-5

Rất nhiều IF, nhưng nếu SVG được mã hóa trước base64 của bạn bắt đầu:

<svg fill="#000000

Sau đó, chuỗi được mã hóa base64 sẽ bắt đầu:

PHN2ZyBmaWxsPSIjMDAwMDAw

nếu chuỗi được mã hóa trước bắt đầu:

<svg fill="#bfa76e

sau đó mã hóa thành:

PHN2ZyBmaWxsPSIjYmZhNzZl

Cả hai chuỗi được mã hóa đều bắt đầu như nhau:

PHN2ZyBmaWxsPSIj

Điểm yếu của mã hóa base64 là cứ 3 ký tự đầu vào trở thành 4 ký tự đầu ra. Với SVG bắt đầu như thế này, màu điền 6 ký tự bắt đầu chính xác trên một 'ranh giới' của khối mã hóa. Do đó, bạn có thể dễ dàng thực hiện thay thế trình duyệt chéo:

output = input.replace(/MDAwMDAw/, "YmZhNzZl");

Nhưng câu trả lời tnt-rox ở trên là cách để tiến về phía trước.

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.