web-dev-qa-db-fra.com

Modifier la couleur de remplissage SVG lorsqu’elle est utilisée comme image de fond

En plaçant la sortie SVG directement en ligne avec le code de page, je peux simplement modifier les couleurs de remplissage avec CSS comme suit:

polygon.mystar {
    fill: blue;
}​

circle.mycircle {
    fill: green;
}

Cela fonctionne très bien, mais je cherche un moyen de modifier l'attribut "remplissage" d'un fichier SVG lorsqu'il est utilisé comme image d'arrière-plan.

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

Comment puis-je changer les couleurs maintenant? Est-ce même possible?

Pour référence, voici le contenu de mon fichier SVG externe:

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

Une façon de faire est de servir votre svg depuis un mécanisme côté serveur. Créez simplement un côté serveur de ressources qui génère votre svg en fonction de paramètres GET, et vous le servirez sur une certaine URL.

Ensuite, vous utilisez simplement cette URL dans votre css.

Parce qu'en fond, img, il ne fait pas partie du DOM et vous ne pouvez pas le manipuler. Une autre possibilité serait de l’utiliser régulièrement, de l’intégrer normalement à une page, mais de le positionner de manière absolue, de lui donner la largeur et la hauteur de la page, puis d’utiliser la propriété z-index css pour la placer derrière tous les autres éléments DOM. sur une page.

64
tonino.j

J'avais besoin de quelque chose de similaire et je voulais rester avec CSS. Voici les mixins LESS et SCSS ainsi que les CSS simples qui peuvent vous aider. Malheureusement, son navigateur est un peu laxiste. Voir ci-dessous pour plus de détails sur la prise en charge du navigateur.

MOINS mixin:

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

MOINS d'utilisation:

.element-color(#fff);

SCSS mixin:

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

Utilisation du SCSS:

@include element-color(#fff);

CSS:

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

Voici plus d'infos sur l'intégration du code SVG complet dans votre fichier CSS. Il a également mentionné la compatibilité de navigateur qui est un peu trop petite pour que cela soit une option viable.

123
Ryan

Vous pouvez utiliser des masques CSS. Avec la propriété 'mask', vous créez un masque qui est appliqué à un élément.

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

Pour plus d'informations, consultez cet article: https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images

57
Adel

Une autre approche consiste à utiliser un masque. Vous modifiez ensuite la couleur d'arrière-plan de l'élément masqué. Cela a le même effet que de modifier l'attribut de remplissage du 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;
}

Vous trouverez un tutoriel complet ici: http://codepen.io/noahblon/blog/coloring-svgs-in-css-background-images (pas le mien). Il propose diverses approches (non limitées au masque).

49
widged

C'est possible avec Sass! La seule chose à faire est de coder l'URL de votre code svg. Et cela est possible avec une fonction d'assistance dans Sass. J'ai fait un codepen pour cela. Regarde ça:

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>');
}
16
Philipp Kühn

Téléchargez votre svg sous forme de texte.

Modifiez votre texte svg en utilisant javascript pour changer les couleurs de peinture/contour/remplissage [s].

Puis intégrez la chaîne svg modifiée inline dans votre css comme décrit ici .

9
jedierikb

Maintenant, vous pouvez réaliser ceci du côté client comme ceci:

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

9
tnt-rox

Vous pouvez stocker le SVG dans une variable. Puis manipulez la chaîne SVG en fonction de vos besoins (c'est-à-dire, définissez la largeur, la hauteur, la couleur, etc.). Puis utilisez le résultat pour définir l’arrière-plan, par ex.

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

J'ai aussi fait une démo, http://sassmeister.com/Gist/4cf0265c5d0143a9e734 .

Ce code émet quelques hypothèses sur le SVG, par exemple. cet élément <svg /> n'a pas de couleur de remplissage existante et aucune propriété de largeur ni de hauteur n'est définie. Comme l'entrée est codée en dur dans le document SCSS, il est assez facile d'appliquer ces contraintes.

Ne vous inquiétez pas de la duplication de code. gzip la compression rend la différence négligeable.

7
Gajus
 .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);
}

article codeben et démo

5
Elbaz

Vous pouvez créer votre propre fonction SCSS pour cela. Ajouter ce qui suit à votre fichier 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

Ensuite, vous pouvez l'utiliser dans votre CSS:

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

Vous devrez éditer vos fichiers SVG et remplacer tous les attributs de remplissage dans le balisage par fill = "{color}".

Le chemin de l'icône est toujours relatif à votre paramètre images_dir dans le même fichier config.rb.

Semblable à certaines des autres solutions, mais c'est assez propre et garde vos fichiers SCSS bien rangés!

3
Lomax

En retard pour le spectacle ici, MAIS, j'ai pu ajouter une couleur de remplissage au polygone SVG, si vous êtes en mesure de modifier directement le code SVG. Ainsi, par exemple, le svg suivant rend le rouge au lieu du noir par défaut. Je n'ai pas testé en dehors de Chrome bien que:

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

Dans certaines situations (très spécifiques), ceci peut être réalisé en utilisant un filtre . Par exemple, vous pouvez changer une image SVG bleue en violet en faisant pivoter la teinte de 45 degrés à l'aide de filter: hue-rotate(45deg);. Le support du navigateur est minime mais reste une technique intéressante.

démo

1

pour un fond monochrome, vous pouvez utiliser un svg avec un masque, où la couleur de fond doit être affichée

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

et que d'utiliser ce css

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