Modifica il colore di riempimento SVG quando viene servito come immagine di sfondo


270

Posizionando l'output SVG direttamente in linea con il codice della pagina sono in grado di modificare semplicemente i colori di riempimento con CSS in questo modo:

polygon.mystar {
    fill: blue;
}​

circle.mycircle {
    fill: green;
}

Funziona benissimo, tuttavia sto cercando un modo per modificare l'attributo "riempimento" di un file SVG quando viene servito come BACKGROUND-IMAGE.

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

Come posso cambiare i colori ora? È anche possibile?

Per riferimento, ecco i contenuti del mio file SVG esterno:

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

Vengo colpito spesso con oggetti di scena per la mia risposta. Dovresti considerare di cambiarlo con la risposta accettata in modo da non perdere.
Ryan,

Risposte:


75

Un modo per farlo è quello di servire il tuo svg da qualche meccanismo lato server. Basta creare un lato server delle risorse che restituisca il tuo svg in base ai parametri GET e lo pubblichi su un determinato URL.

Quindi basta usare quell'URL nel tuo CSS.

Perché come img di sfondo, non fa parte del DOM e non puoi manipolarlo. Un'altra possibilità sarebbe quella di usarlo regolarmente, incorporarlo in una pagina in modo normale, ma posizionarlo assolutamente, renderlo a tutta larghezza e altezza di una pagina e quindi utilizzare la proprietà css z-index per metterlo dietro tutti gli altri elementi DOM su una pagina.


7
Non dimenticare se stai offrendo l'SVG da uno script sul lato server, per assicurarti di inviare anche l' intestazione MIME corretta . In PHP questo sarebbe:<?php header('Content-type: image/svg+xml'); ?>
Saul Fautley il

4
Puoi usare l'immagine svg come maschera e manipolare il colore di sfondo dell'elemento. Ciò avrà lo stesso effetto della modifica del riempimento. (risposta dettagliata fornita)
ampliato il

16
Questa risposta è stata eccezionale dal 2012, ma ora le maschere e / o i filtri CSS sono supportati da tempo in tutti i browser. Consiglio a chiunque legga questo ora di controllare i collegamenti nella risposta di widged di seguito o semplicemente saltare alle maschere CSS qui , che è una soluzione davvero semplice - nota che richiede ancora 2 versioni della regola, una con al momento -webkit- prefisso al momento tempo. Per Microsoft Edge, attualmente sono supportati i filtri CSS ma non ancora le maschere.
joelhardi,

2
Ci sono molte soluzioni che forniscono il muggito che funziona al giorno d'oggi, sono d'accordo che questa risposta non riflette più lo stato attuale delle possibilità.
David Neto,

148

Avevo bisogno di qualcosa di simile e volevo attenermi ai CSS. Ecco i mixin MENO e SCSS, nonché i semplici CSS che possono aiutarti in questo. Sfortunatamente, il supporto del browser è un po 'rilassato. Vedi sotto per i dettagli sul supporto del browser.

MENO mixin:

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

MENO utilizzo:

.element-color(#fff);

Mixin SCSS:

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

Utilizzo SCSS:

@include element-color(#fff);

CSS:

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

Ecco ulteriori informazioni sull'incorporamento del codice SVG completo nel tuo file CSS. Ha anche menzionato la compatibilità del browser che è un po 'troppo piccola per essere un'opzione praticabile.


Anche se c'è un po 'di sovraccarico, perché devo codificare tutti gli elementi svg, penso che questa sia la soluzione migliore per un po'. Grazie
Adriano Rosa,

È necessario utilizzare un preprocessore CSS come Sass o Less se si desidera utilizzare in questo modo. Se non ne usi uno, dovrai solo usare quella linea di immagine di sfondo per ogni colore
Codice

36
Nota che è necessario urlencode il #carattere per i tuoi colori esadecimali per farlo funzionare in Firefox. Quindi qualcosa del genere <svg fill="#ffffff" ...></svg>diventa <svg fill="%23ffffff" ...></svg>.
Swen,

1
Metodo dolce. Devi codificare con forza lo svg nell'immagine di sfondo in quel modo? Non puoi semplicemente collegarti ad esso in qualche modo?
Luca,

2
Ho trovato questo sito utile per darti l'URL perfettamente codificato pronto per l'uso: yoksel.github.io/url-encoder - Copia semplicemente il codice SVG in esso e copia il CSS restituito :-)
Codice

96

Puoi usare le maschere CSS, con la proprietà 'mask' puoi creare una maschera che viene applicata a un elemento.

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

Per ulteriori informazioni, consulta questo fantastico articolo: https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images


3
questo è buono ma quando applicato a un'icona all'interno di un campo di input tutto il testo di input è nascosto.
raison,

14
Non supportato in IE
Kareem il

Risposta super cool, ma non puoi più usare il colore di sfondo in un passaggio del mouse o qualcosa del genere
Paul Kruger

Questo sembra essere a malapena supportato se non altro - troppi utenti non sarebbero in grado di vederlo perché sia ​​praticabile oggi alla fine del 2018. caniuse.com/#feat=css-masks
Chris Moschini

3
Estate 2019: il 94% dei browser su questo pianeta supporta gli stili "maschera-immagine" OPPURE "-webkit-maschera-immagine"
Dmitry Kulahin

57

Ancora un altro approccio è usare la maschera. Quindi si modifica il colore di sfondo dell'elemento mascherato. Ciò ha lo stesso effetto della modifica dell'attributo fill dello 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;
}

Troverai un tutorial completo qui: http://codepen.io/noahblon/blog/coloring-svgs-in-css-background-images (non mio). Propone una varietà di approcci (non limitato alla maschera).


11
Una cosa da notare al riguardo è il supporto del browser. Credo che IE (come al solito) sia molto indietro su questo.
Matthew Johnson,

9
Sfortunatamente masknon è supportato da IE né Edge: caniuse.com/#search=mask
alpipego

Non funziona neanche per me in Chrome. Modifica: Oh nvm ... Non ho abilitato la correzione automatica. Pensavo che i venditori avrebbero dovuto smettere di usare i prefissi ?!
Aprire il

Lavori in ultima Chrome e Firefox
tic

16

È possibile con Sass! L'unica cosa che devi fare è url codificare il tuo codice svg. E questo è possibile con una funzione di supporto in Sass. Ho creato un codice per questo. Guarda questo:

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
Funziona molto bene. Unico problema: in IE10 l'icona è troppo piccola (penso che il 10% della dimensione data.
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);
}

articolo e demo di codeben


1
Questo metodo applicherà il filtro a un intero oggetto, inclusi i bambini.
Krzysztof Antoniak,

9

Scarica il tuo svg come testo.

Modifica il tuo testo svg usando javascript per cambiare il colore di vernice / tratto / riempimento [s].

Quindi incorpora la stringa svg modificata in linea nel tuo CSS come descritto qui .


9

Ora puoi farlo sul lato client in questo modo:

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

Vieni qui!


1
Dovresti evitare l'uso di Base64 per SVG in quanto non è necessario, ingrandisce i tuoi file e persino impedisce a GZIP di comprimere efficacemente quei blocchi di codice.
entro il

1
Questa codifica sta avvenendo sul lato client, probabilmente solo per una completa evasione ...
diachedelic,

Inutile dire che puoi fare qualsiasi cosa con JS. Il punto è evitare JS.
MarsAndBack

7

È possibile memorizzare SVG in una variabile. Quindi manipola la stringa SVG in base alle tue esigenze (ad esempio, imposta larghezza, altezza, colore, ecc.). Quindi utilizzare il risultato per impostare lo sfondo, ad es

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

Ho anche fatto una demo, http://sassmeister.com/gist/4cf0265c5d0143a9e734 .

Questo codice fa alcune ipotesi sull'SVG, ad esempio che l' <svg />elemento non ha un colore di riempimento esistente e che non sono impostate né le proprietà di larghezza né altezza. Poiché l'input è codificato nel documento SCSS, è abbastanza semplice applicare questi vincoli.

Non preoccuparti della duplicazione del codice. la compressione rende la differenza trascurabile.


Il codice duplicato è un odore di codice, quindi suggerire che le persone non dovrebbero preoccuparsi del codice duplicato nel caso del tuo esempio non è una buona idea, tuttavia che ha detto che non riesco a vedere dove è duplicato il tuo codice? Penso che avrebbe letto meglio se avessi rimosso del tutto il commento.
Professore di programmazione il

3

È possibile creare la propria funzione SCSS per questo. Aggiungendo quanto segue al tuo file config.rb.

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

Quindi puoi usarlo nel tuo CSS:

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

Dovrai modificare i tuoi file SVG e sostituire eventuali attributi di riempimento nel markup con fill = "{color}"

Il percorso dell'icona è sempre relativo al parametro images_dir nello stesso file config.rb.

Simile ad alcune altre soluzioni, ma è abbastanza pulito e mantiene in ordine i tuoi file SCSS!


1
questo è da un problema di github . Basta fare riferimento qui nel caso qualcuno voglia leggere la discussione lì
MMachinegun,

2

In alcune situazioni (molto specifiche) questo potrebbe essere ottenuto usando un filtro . Ad esempio, è possibile cambiare un'immagine SVG blu in viola ruotando la tonalità di 45 gradi usando filter: hue-rotate(45deg);. Il supporto del browser è minimo ma è ancora una tecnica interessante.

dimostrazione


2

per lo sfondo monocromatico è possibile utilizzare uno svg con una maschera, in cui deve essere visualizzato il colore di sfondo

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

e che usare questo css

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


1

In ritardo allo spettacolo qui, MA, sono stato in grado di aggiungere un colore di riempimento al poligono SVG, se sei in grado di modificare direttamente il codice SVG, quindi ad esempio il seguente svg rende rosso, anziché nero predefinito. Non ho testato al di fuori di Chrome però:

<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

Questo è il mio metodo preferito, ma il supporto del tuo browser deve essere molto progressivo. Con la proprietà maschera si crea una maschera che viene applicata a un elemento. Ovunque la maschera è opaca o solida, l'immagine sottostante mostra attraverso. Dove è trasparente, l'immagine sottostante viene mascherata o nascosta. La sintassi per un'immagine maschera CSS è simile all'immagine di sfondo. guarda il codepenmask


-5

Molti IF, ma se inizia il tuo SVG con codifica pre base64:

<svg fill="#000000

Quindi inizierà la stringa codificata base64:

PHN2ZyBmaWxsPSIjMDAwMDAw

se inizia la stringa pre-codificata:

<svg fill="#bfa76e

quindi questo codifica per:

PHN2ZyBmaWxsPSIjYmZhNzZl

Entrambe le stringhe codificate iniziano allo stesso modo:

PHN2ZyBmaWxsPSIj

La stranezza della codifica base64 è che ogni 3 caratteri di input diventano 4 caratteri di output. Con lo SVG che inizia in questo modo, il colore di riempimento esadecimale di 6 caratteri inizia esattamente su un 'confine' di blocco di codifica. Quindi puoi facilmente fare una sostituzione JS cross-browser:

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

Ma la risposta tnt-rox sopra è il modo per andare avanti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.