Arka Plan Resmi olarak sunulduğunda SVG dolgu rengini değiştirme


270

SVG çıktısını doğrudan sayfa koduyla yerleştirme Ben sadece dolgu renklerini CSS ile şu şekilde değiştirebiliyorum:

polygon.mystar {
    fill: blue;
}​

circle.mycircle {
    fill: green;
}

Bu harika çalışıyor, ancak bir SVG "ARKA PLAN-GÖRÜNTÜ" olarak sunulurken "dolgu" özniteliğini değiştirmek için bir yol arıyorum.

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

Renkleri şimdi nasıl değiştirebilirim? Hatta mümkün mü?

Referans olarak, harici SVG dosyamın içeriğ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>

Cevabım için sık sık sahne alınıyor. Cevapsız kabul edilmemesi için kabul edilen cevaba değiştirmeyi düşünmelisiniz.
Ryan

Yanıtlar:


75

Bunu yapmanın bir yolu, svg'nize bazı sunucu tarafı mekanizmalarından hizmet etmektir. Svg'nizi GET parametrelerine göre çıkaran bir kaynak sunucu tarafı oluşturun ve belirli bir URL'de sunun.

Sonra sadece bu URL'yi css'nizde kullanın.

Çünkü arka plan img'si olarak, DOM'un bir parçası değildir ve onu değiştiremezsiniz. Başka bir olasılık, düzenli olarak kullanmak, bir sayfaya normal bir şekilde gömmek, ancak kesinlikle konumlandırmak, bir sayfanın tam genişliğini ve yüksekliğini yapmak ve ardından diğer tüm DOM öğelerinin arkasına koymak için z-index css özelliğini kullanmak olabilir. bir sayfada.


7
Doğru MIME üstbilgisini de gönderdiğinizden emin olmak için SVG'yi sunucu tarafı komut dosyasından sunuyorsanız unutmayın . PHP bu olurdu:<?php header('Content-type: image/svg+xml'); ?>
Saul Fautley

4
Svg görüntüsünü maske olarak kullanabilir ve öğenin arka plan rengini değiştirebilirsiniz. Bu, dolguyu değiştirmekle aynı etkiye sahip olacaktır. (ayrıntılı cevap verilir)
genişletilmiş

16
Bu yanıt 2012 itibariyle harikaydı, ancak şimdi CSS maskeleri ve / veya filtreleri bir süredir tüm tarayıcılarda destekleniyor. Bunu şimdi okuyan herkesin aşağıdaki geniş cevaptaki bağlantılara göz atmasını veya burada CSS Maskeleri'ne geçmesini tavsiye ederim , bu gerçekten kolay bir çözümdür - hala kuralın 2 sürümünü gerektirir, bir tanesi şu anda -webkit- öneki var zaman. Microsoft Edge için şu anda CSS filtreleri destekleniyor, ancak henüz maskeler desteklenmiyor.
joelhardi

2
Günümüzde işe yarayan birçok çözüm var, bu cevabın artık mevcut olasılıkları yansıtmadığına katılıyorum.
David Neto

148

Benzer bir şeye ihtiyacım vardı ve CSS'ye bağlı kalmak istedim. İşte size bu konuda yardımcı olabilecek LESS ve SCSS karışımlarının yanı sıra sade CSS. Ne yazık ki, tarayıcı desteği biraz gevşek. Tarayıcı desteği ile ilgili ayrıntılar için aşağıya bakın.

DAHA AZ karışım:

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

DAHA AZ kullanım:

.element-color(#fff);

SCSS karışımı:

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

SCSS kullanımı:

@include element-color(#fff);

CSS:

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

İşte tam SVG kodunu CSS dosyanıza gömme hakkında daha fazla bilgi . Ayrıca bunun uygun bir seçenek olması için biraz küçük olan tarayıcı uyumluluğundan da bahsetti.


Her ne kadar biraz ek yük olsa da, tüm svg öğelerini kodlamak zorunda olduğum için, bunun bir süre için en iyi çözüm olduğunu düşünüyorum. Teşekkürler
Adriano Rosa

Bu şekilde kullanmak istiyorsanız Sass veya Less gibi bir CSS ön işlemcisi kullanmanız gerekir. Birini kullanmıyorsanız, her renk için o arka plan resmi satırını kullanmanız gerekir
Dostça Kod

36
#Firefox'ta çalışmasını sağlamak için onaltılık renklerinizin karakterini kodlamanız gerektiğini unutmayın . Yani böyle bir şey <svg fill="#ffffff" ...></svg>olur <svg fill="%23ffffff" ...></svg>.
Swen

1
Tatlı yöntem. Svg'yi böyle bir arka plan görüntüsüne zorla kodlamak zorunda mısınız? Sadece bir şekilde bağlantı kuramaz mısın?
Luke

2
Bu siteyi size kullanıma hazır mükemmel kodlanmış URL'yi vermek için yararlı buldum: yoksel.github.io/url-encoder - SVG kodunu kopyalayın ve iade edilen CSS'yi kopyalayın :-)
Kolay Kod

95

CSS maskelerini kullanabilirsiniz, 'mask' özelliği ile bir öğeye uygulanan bir maske oluşturursunuz.

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

Daha fazla bilgi için bu harika makaleye bakın: https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images


3
bu iyidir, ancak bir giriş alanındaki bir simgeye uygulandığında tüm giriş metni gizlenir.
raison

14
IE'de desteklenmiyor
Kareem

Süper harika cevap, ancak artık vurgulu veya benzeri bir şeyde arka plan rengini kullanamazsınız
Paul Kruger

Çok az kullanıcı bugün 2018'in
Chris

3
Yaz 2019: Bu gezegendeki tarayıcıların% 94'ü "maske görüntüsü" VEYA "-webkit-maske-görüntüsü" stillerini
destekliyor

57

Yine başka bir yaklaşım maske kullanmaktır. Daha sonra maskelenen öğenin arka plan rengini değiştirirsiniz. Bu, svg'nin fill özelliğini değiştirmekle aynı etkiye sahiptir.

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

Burada tam bir öğretici bulacaksınız: http://codepen.io/noahblon/blog/coloring-svgs-in-css-background-images (benim değil). Çeşitli yaklaşımlar önerir (maske ile sınırlı değildir).


11
Bu konuda dikkat edilmesi gereken bir şey tarayıcı desteğidir. IE (her zamanki gibi) bu konuda arkasında olduğuna inanıyorum.
Matthew Johnson

9
Ne yazık ki maskne IE ne de Edge tarafından desteklenmiyor: caniuse.com/#search=mask
alpipego

Chrome'da da benim için çalışmıyor. Düzenleme: Oh nvm ... Otomatik düzeltici etkin değil. Satıcıların önek kullanmayı bırakmaları gerektiğini düşündüm ?!
17'de

En son krom ve firefox'ta çalışır
tic

16

Sass ile mümkün! Yapmanız gereken tek şey svg kodunuzu url-kodlamak. Ve bu Sass'ta bir yardımcı işlev ile mümkündür. Bunun için bir kodlama yaptım. Şuna bak:

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
Bu çok iyi çalışıyor. Tek sorun: IE10'da simge çok küçük (verilen boyutun% 10'unu düşünüyorum.
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);
}

codeben makalesi ve demosu


1
Bu yöntem, çocuklar dahil tüm nesneye filtre uygular.
Krzysztof Antoniak

9

Svg'nizi metin olarak indirin.

Boya / kontur / dolgu rengini değiştirmek için svg metninizi javascript kullanarak değiştirin.

Daha sonra değiştirilmiş svg dizesini satır içi olarak burada açıklandığı gibi css'nize gömün .


9

Şimdi bunu müşteri tarafında şöyle yapabilirsiniz:

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

Burada keman!


1
SVG için Base64 kullanmaktan kaçınmalısınız, çünkü gereksizdir, dosyalarınızı büyütür ve hatta GZIP'in bu kod parçalarını etkili bir şekilde sıkıştırmasını önler.
inta

1
Bu kodlama istemci tarafında, muhtemelen sadece tam kaçmak için oluyor ...
diachedelic

JS ile her şeyi yapabileceğinizi söylemeye gerek yok. Mesele JS'den kaçınmaktır.
MarsAndBack

7

SVG'yi bir değişkende saklayabilirsiniz. Ardından SVG dizesini ihtiyaçlarınıza bağlı olarak değiştirin (yani genişliği, yüksekliği, rengi ayarlayın). Ardından, arka planı ayarlamak için sonucu kullanın, örn.

$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)}');
  }
}

Ben de bir demo yaptım, http://sassmeister.com/gist/4cf0265c5d0143a9e734 .

Bu kod, SVG hakkında birkaç varsayım yapar, örneğin bu <svg />öğenin mevcut dolgu rengi yoktur ve hiçbir genişlik veya yükseklik özelliği ayarlanmamıştır. Girdi SCSS belgesinde sabit olarak kodlandığından, bu kısıtlamaları uygulamak oldukça kolaydır.

Kod çoğaltma konusunda endişelenmeyin. sıkıştırma farkı ihmal edilebilir kılar.


Yinelenen kod bir kod kokusudur, bu nedenle, örneğin örneğinizin yinelenen kod hakkında endişelenmemesi gerektiğini düşündüren iyi bir fikir değildir, ancak kodunuzun nerede çoğaltıldığını göremiyorum? Yorumu tamamen kaldırırsanız daha iyi olacağını düşünüyorum.
programlama profesörü

3

Bunun için kendi SCSS işlevinizi oluşturabilirsiniz. Aşağıdakileri config.rb dosyanıza ekleme.

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

Ardından CSS'nizde kullanabilirsiniz:

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

SVG dosyalarınızı düzenlemeniz ve biçimlendirmedeki dolgu niteliklerini fill = "{color}" ile değiştirmeniz gerekecektir.

Simge yolu her zaman aynı config.rb dosyasındaki images_dir parametrenize göredir.

Diğer bazı çözümlere benzer, ancak bu oldukça temiz ve SCSS dosyalarınızı düzenli tutar!


1
bu bir github sorunudur . Birinin orada tartışmayı okumak
istemesi

2

Bazı (çok spesifik) durumlarda bu bir filtre kullanılarak gerçekleştirilebilir . Örneğin, tonu kullanarak 45 dereceyi döndürerek mavi bir SVG görüntüsünü mor olarak değiştirebilirsiniz filter: hue-rotate(45deg);. Tarayıcı desteği minimaldir ancak yine de ilginç bir tekniktir.

gösteri


2

tek renkli arka plan için, arka plan renginin görüntülenmesi gereken bir maske ile bir svg kullanabilirsiniz

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

ve bu css kullanmaktan

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


1

Buradaki şovun sonlarına doğru, ancak SVG kodunu doğrudan düzenleyebiliyorsanız, SVG poligonuna bir dolgu rengi ekleyebildim, örneğin aşağıdaki svg varsayılan siyah yerine kırmızıya dönüşür. Yine de Chrome dışında test etmedim:

<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

Bu benim en sevdiğim yöntem, ancak tarayıcı desteğiniz çok ilerici olmalı. Mask özelliği ile, bir öğeye uygulanan bir maske oluşturursunuz. Maskenin opak veya katı olduğu her yerde, alttaki görüntü gösterilir. Saydam olduğunda, alttaki görüntü maskelenir veya gizlenir. Bir CSS maske görüntüsünün sözdizimi arka plan görüntüsüne benzer. kod alanına bakmask


-5

Çok sayıda IF, ancak ön base64 kodlu SVG'niz başlarsa:

<svg fill="#000000

Sonra base64 kodlu dize başlayacaktır:

PHN2ZyBmaWxsPSIjMDAwMDAw

önceden kodlanmış dize başlarsa:

<svg fill="#bfa76e

sonra bu kodlama:

PHN2ZyBmaWxsPSIjYmZhNzZl

Her iki kodlanmış dize aynı şekilde başlar:

PHN2ZyBmaWxsPSIj

Base64 kodlamasının tuhaflığı her 3 giriş karakterinin 4 çıkış karakteri haline gelmesidir. SVG böyle başladığında, 6 karakterlik altıgen dolgu rengi tam olarak bir kodlama bloğu 'sınırında' başlar. Bu nedenle kolayca çapraz tarayıcı JS yerine yapabilirsiniz:

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

Ancak yukarıdaki tnt-rox cevabı ilerlemenin yoludur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.