Ändern Sie die SVG-Füllfarbe, wenn Sie als Hintergrundbild bereitgestellt werden

270

Platzieren der SVG-Ausgabe direkt inline mit dem Seitencode Ich kann Füllfarben mit CSS einfach so ändern:

polygon.mystar {
    fill: blue;
}​

circle.mycircle {
    fill: green;
}

Dies funktioniert hervorragend, ich suche jedoch nach einer Möglichkeit, das Attribut "fill" eines SVG zu ändern, wenn es als BACKGROUND-IMAGE bereitgestellt wird.

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

Wie kann ich jetzt die Farben ändern? Ist es überhaupt möglich?

Als Referenz hier der Inhalt meiner externen SVG-Datei:

<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>
Joe
quelle
Ich werde oft mit Requisiten für meine Antwort getroffen. Sie sollten in Betracht ziehen, es in die akzeptierte Antwort zu ändern, damit es nicht übersehen wird.
Ryan

Antworten:

75

Eine Möglichkeit, dies zu tun, besteht darin, Ihr SVG von einem serverseitigen Mechanismus aus zu bedienen. Erstellen Sie einfach eine Ressourcenserverseite, die Ihr SVG gemäß den GET-Parametern ausgibt, und Sie stellen es unter einer bestimmten URL bereit.

Dann verwenden Sie einfach diese URL in Ihrem CSS.

Weil es als Hintergrundbild nicht Teil des DOM ist und Sie es nicht manipulieren können. Eine andere Möglichkeit wäre, es regelmäßig zu verwenden, es auf normale Weise in eine Seite einzubetten, es aber absolut zu positionieren, die volle Breite und Höhe einer Seite festzulegen und dann die CSS-Eigenschaft z-index zu verwenden, um es hinter alle anderen DOM-Elemente zu setzen auf einer Seite.

tonino.j
quelle
7
Vergessen Sie nicht, wenn Sie die SVG-Datei über ein serverseitiges Skript bereitstellen, um sicherzustellen, dass Sie auch den richtigen MIME-Header senden . In PHP wäre dies:<?php header('Content-type: image/svg+xml'); ?>
Saul Fautley
4
Sie können das SVG-Bild als Maske verwenden und die Hintergrundfarbe des Elements bearbeiten. Dies hat den gleichen Effekt wie das Ändern der Füllung. (detaillierte Antwort zur Verfügung gestellt)
erweitert
16
Diese Antwort war ab 2012 großartig, aber jetzt werden CSS-Masken und / oder Filter seit einiger Zeit in allen Browsern unterstützt. Ich empfehle , dass jemand dies lesen jetzt die Links Besuche in Antwort des widged unten oder überspringen , nur um CSS - Masken hier , die eine wirklich einfache Lösung ist - Anmerkung es noch erfordert 2 Version der Regel ein mit -webkit- Präfix in der Gegenwart Zeit. Für Microsoft Edge werden derzeit CSS-Filter unterstützt, jedoch noch keine Masken.
Joelhardi
2
Es gibt viele Lösungen, die heutzutage funktionieren. Ich stimme zu, dass diese Antwort nicht mehr den aktuellen Stand der Möglichkeiten widerspiegelt.
David Neto
148

Ich brauchte etwas Ähnliches und wollte bei CSS bleiben. Hier finden Sie WENIGER- und SCSS-Mixins sowie einfaches CSS, das Ihnen dabei helfen kann. Leider ist die Browserunterstützung etwas lasch. Weitere Informationen zur Browserunterstützung finden Sie weiter unten.

WENIGER mixin:

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

WENIGER Verwendung:

.element-color(#fff);

SCSS-Mixin:

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

SCSS-Verwendung:

@include element-color(#fff);

CSS:

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

Hier finden Sie weitere Informationen zum Einbetten des vollständigen SVG-Codes in Ihre CSS-Datei. Es wurde auch die Browserkompatibilität erwähnt, die etwas zu klein ist, als dass dies eine praktikable Option wäre.

Ryan
quelle
Obwohl es einen kleinen Overhead gibt, weil ich alle SVG-Elemente fest codieren muss, denke ich, dass dies für eine Weile die beste Lösung ist. Danke
Adriano Rosa
Sie müssen einen CSS-Präprozessor wie Sass oder Less verwenden, wenn Sie auf diese Weise verwenden möchten. Wenn Sie keine verwenden, müssen Sie nur diese Hintergrundbildzeile für jede Farbe verwenden
Friendly Code
34
Beachten Sie, dass Sie das #Zeichen für Ihre Hex-Farben urlencodieren müssen , damit dies in Firefox funktioniert. So <svg fill="#ffffff" ...></svg>wird so etwas wie <svg fill="%23ffffff" ...></svg>.
Swen
1
Süße Methode. Müssen Sie das SVG so hart in das Hintergrundbild kodieren? Kannst du nicht einfach irgendwie darauf verlinken?
Luke
2
Ich fand diese Seite nützlich, um Ihnen die perfekt codierte URL zur Verfügung zu stellen: yoksel.github.io/url-encoder - Kopieren Sie einfach den SVG-Code hinein und kopieren Sie das zurückgegebene CSS aus :-)
Friendly Code
94

Sie können CSS-Masken verwenden. Mit der Eigenschaft 'mask' erstellen Sie eine Maske, die auf ein Element angewendet wird.

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

Weitere Informationen finden Sie in diesem großartigen Artikel: https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images

Adel
quelle
3
Dies ist gut, aber wenn es auf ein Symbol in einem Eingabefeld angewendet wird, wird der gesamte Eingabetext ausgeblendet.
Existenzberechtigung
14
Nicht unterstützt in IE
Kareem
Super coole Antwort, aber Sie können keine Hintergrundfarbe mehr in einem Schwebeflug oder so etwas verwenden
Paul Kruger
Dies scheint kaum unterstützt zu werden, wenn überhaupt - zu viele Benutzer würden dies nicht sehen können, als dass es heute Ende 2018 realisierbar wäre. Caniuse.com/#feat=css-masks
Chris Moschini
3
Sommer 2019: 94% der Browser auf diesem Planeten unterstützen "Maskenbild" ODER "Webkit-Maskenbild" -Stile
Dmitry Kulahin
57

Ein weiterer Ansatz ist die Verwendung einer Maske. Anschließend ändern Sie die Hintergrundfarbe des maskierten Elements. Dies hat den gleichen Effekt wie das Ändern des Füllattributs des 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;
}

Ein vollständiges Tutorial finden Sie hier: http://codepen.io/noahblon/blog/coloring-svgs-in-css-background-images (nicht mein eigenes). Es werden verschiedene Ansätze vorgeschlagen (nicht auf Masken beschränkt).

verwitwet
quelle
11
Eine Sache, die Sie dabei beachten sollten, ist die Browserunterstützung. Ich glaube, dass IE (wie üblich) weit dahinter liegt.
Matthew Johnson
9
Leider maskwird weder von IE noch von Edge unterstützt: caniuse.com/#search=mask
alpipego
Funktioniert auch nicht für mich in Chrome. Edit: Oh nvm ... Ich habe Autoprefixer nicht aktiviert. Ich dachte, Anbieter sollten keine Präfixe mehr verwenden?!
Mpen
Arbeiten in neuesten Chrome und Firefox
tic
16

Mit Sass ist das möglich! Das einzige, was Sie tun müssen, ist die URL-Codierung Ihres SVG-Codes. Und das ist mit einer Helferfunktion in Sass möglich. Ich habe dafür einen Codepen gemacht. Schau dir das an:

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>');
}
Philipp Kühn
quelle
2
Das funktioniert sehr gut. Einziges Problem: In IE10 ist das Symbol viel zu klein (ich denke 10% der angegebenen Größe.
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 Artikel und Demo

Elbaz
quelle
1
Diese Methode wendet Filter auf ein ganzes Objekt an, einschließlich untergeordneter Objekte.
Krzysztof Antoniak
9

Laden Sie Ihre SVG als Text herunter.

Ändern Sie Ihren SVG-Text mit Javascript, um die Farbe / Strich / Füllfarbe (n) zu ändern.

Betten Sie dann die geänderte SVG-Zeichenfolge wie hier beschrieben in Ihr CSS ein .

jedierikb
quelle
9

Jetzt können Sie dies auf der Client-Seite folgendermaßen erreichen:

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

Geige hier!

tnt-rox
quelle
1
Sie sollten die Verwendung von Base64 für SVG vermeiden, da dies nicht erforderlich ist, Ihre Dateien vergrößert und sogar verhindert, dass GZIP diese Codestücke effektiv komprimiert.
Inta
1
Diese Kodierung geschieht auf der Client-Seite, wahrscheinlich nur, um gründlich zu entkommen ...
diachedelisch
Es versteht sich von selbst, dass Sie mit JS alles machen können. Der Punkt ist, JS zu vermeiden.
MarsAndBack
7

Sie können die SVG in einer Variablen speichern. Bearbeiten Sie dann die SVG-Zeichenfolge je nach Ihren Anforderungen (dh stellen Sie Breite, Höhe, Farbe usw. ein). Verwenden Sie dann das Ergebnis, um den Hintergrund festzulegen, z

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

Ich habe auch eine Demo gemacht, http://sassmeister.com/gist/4cf0265c5d0143a9e734 .

Dieser Code macht einige Annahmen über die SVG, z. B. dass das <svg />Element keine Füllfarbe hat und weder die Eigenschaften für Breite noch Höhe festgelegt sind. Da die Eingabe im SCSS-Dokument fest codiert ist, ist es recht einfach, diese Einschränkungen durchzusetzen.

Machen Sie sich keine Sorgen über die Codeduplizierung. Komprimierung macht den Unterschied vernachlässigbar.

Gajus
quelle
Doppelter Code ist ein Codegeruch, daher ist es keine gute Idee, den Leuten vorzuschlagen, dass sie sich im Fall Ihres Beispiels keine Gedanken über doppelten Code machen sollten. Allerdings kann ich nicht sehen, wo Ihr Code dupliziert wird. Ich denke, es würde besser lesen, wenn Sie den Kommentar einfach ganz entfernen würden.
Professor für Programmierung
3

Hierfür können Sie eine eigene SCSS-Funktion erstellen. Fügen Sie Ihrer config.rb-Datei Folgendes hinzu.

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

Dann können Sie es in Ihrem CSS verwenden:

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

Sie müssen Ihre SVG-Dateien bearbeiten und alle Füllattribute im Markup durch fill = "{color}" ersetzen.

Der Symbolpfad ist immer relativ zu Ihrem Parameter images_dir in derselben Datei config.rb.

Ähnlich wie bei einigen anderen Lösungen, aber dies ist ziemlich sauber und hält Ihre SCSS-Dateien aufgeräumt!

Lomax
quelle
1
Dies ist aus einem Github-Problem .
Ich beziehe mich
2

In einigen (sehr spezifischen) Situationen kann dies durch Verwendung eines Filters erreicht werden . Sie können beispielsweise ein blaues SVG-Bild in lila ändern, indem Sie den Farbton mit um 45 Grad drehen filter: hue-rotate(45deg);. Die Browserunterstützung ist minimal, aber immer noch eine interessante Technik.

Demo

Michaël van de Weerd
quelle
2

Für monochromen Hintergrund können Sie ein SVG mit einer Maske verwenden, in der die Hintergrundfarbe angezeigt werden soll

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

und dann benutze dieses CSS

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

Spät zur Show hier, ABER, konnte ich dem SVG-Polygon eine Füllfarbe hinzufügen, wenn Sie den SVG-Code direkt bearbeiten können, sodass beispielsweise das folgende SVG Rot anstelle von Standardschwarz rendert. Ich habe jedoch nicht außerhalb von Chrome getestet:

<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>
Eleanor Zimmermann
quelle
-2

Dies ist meine Lieblingsmethode, aber Ihre Browserunterstützung muss sehr fortschrittlich sein. Mit der mask-Eigenschaft erstellen Sie eine Maske, die auf ein Element angewendet wird. Überall dort, wo die Maske undurchsichtig oder fest ist, wird das zugrunde liegende Bild durchscheint. Wo es transparent ist, wird das zugrunde liegende Bild ausgeblendet oder ausgeblendet. Die Syntax für ein CSS-Maskenbild ähnelt dem Hintergrundbild. Schau dir den Codepen anmask

Mebin Benny
quelle
-5

Viele IFs, aber wenn Ihr vor base64 codiertes SVG startet:

<svg fill="#000000

Dann beginnt die Base64-codierte Zeichenfolge:

PHN2ZyBmaWxsPSIjMDAwMDAw

Wenn die vorcodierte Zeichenfolge beginnt:

<svg fill="#bfa76e

dann codiert dies zu:

PHN2ZyBmaWxsPSIjYmZhNzZl

Beide codierten Zeichenfolgen beginnen gleich:

PHN2ZyBmaWxsPSIj

Die Besonderheit der Base64-Codierung besteht darin, dass alle 3 Eingabezeichen zu 4 Ausgabezeichen werden. Wenn das SVG so beginnt, beginnt die 6-stellige Hex-Füllfarbe genau an einer Codierungsblock-Grenze. Daher können Sie problemlos einen browserübergreifenden JS-Ersatz durchführen:

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

Aber die obige Antwort von tnt-rox ist der Weg, um vorwärts zu kommen.

A2D
quelle