Изменить цвет заливки SVG, когда он используется в качестве фонового изображения


270

Помещая вывод SVG прямо в линию с кодом страницы, я могу просто изменить цвета заливки с помощью CSS следующим образом:

polygon.mystar {
    fill: blue;
}​

circle.mycircle {
    fill: green;
}

Это прекрасно работает, однако я ищу способ изменить атрибут "fill" SVG, когда он используется как BACKGROUND-IMAGE.

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

Как я могу изменить цвета сейчас? Это вообще возможно?

Для справки, вот содержимое моего внешнего файла 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="#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>

Меня часто бьют реквизитом за мой ответ. Вы должны рассмотреть вопрос об изменении его на принятый ответ, чтобы он не был пропущен.
— Райан

Ответы:


75

Один из способов сделать это состоит в том, чтобы обслуживать ваш svg с какого-либо серверного механизма. Просто создайте сторону сервера ресурсов, которая выводит ваш svg в соответствии с параметрами GET, и вы обслуживаете его по определенному URL.

Тогда вы просто используете этот URL в вашем CSS.

Потому что как фоновое изображение, оно не является частью DOM, и вы не можете им манипулировать. Другой возможностью было бы использовать его регулярно, встраивать его в страницу обычным способом, но расположить его абсолютно, сделать его шириной и высотой страницы, а затем использовать свойство z-index css, чтобы поместить его позади всех других элементов DOM. на странице.


7
Не забудьте, если вы обслуживаете SVG из серверного скрипта, чтобы убедиться, что вы также отправляете правильный заголовок MIME . В PHP это было бы:<?php header('Content-type: image/svg+xml'); ?>
— Сол Fautley

4
Вы можете использовать изображение svg в качестве маски и управлять цветом фона элемента. Это будет иметь тот же эффект, что и изменение заливки. (подробный ответ предоставлен)
— зарезервировано

16
Этот ответ был великолепен с 2012 года, но теперь CSS-маски и / или фильтры поддерживаются во всех браузерах в течение некоторого времени. Я рекомендую всем, кто читает это сейчас, проверить ссылки в ответе widged ниже или просто перейти к CSS Masks здесь , что является действительно простым решением - обратите внимание, что для него все еще требуется 2 версии правила, одна с префиксом -webkit- в настоящее время время. Для Microsoft Edge в настоящее время фильтры CSS поддерживаются, но еще не маскируются.
— Джоэлхарди

2
В настоящее время существует множество решений, которые работают, и я согласен, что этот ответ больше не отражает текущее состояние возможностей.
— Дэвид Нето

148

Мне нужно что-то подобное и хотел придерживаться CSS. Вот миксины LESS и SCSS, а также простой CSS, который может помочь вам в этом. К сожалению, поддержка браузера немного слабовата. Подробнее о поддержке браузера смотрите ниже.

Меньше миксин:

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

МЕНЬШЕЕ использование:

.element-color(#fff);

SCSS mixin:

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

Использование SCSS:

@include element-color(#fff);

CSS:

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

Вот дополнительная информация о встраивании полного кода SVG в ваш файл CSS. Он также упомянул совместимость браузера, которая слишком мала, чтобы это было приемлемым вариантом.


Хотя есть некоторые накладные расходы, потому что я должен жестко закодировать все элементы SVG, я думаю, что это лучшее решение на некоторое время. Спасибо
— Адриано Роза

Вам нужно использовать CSS-препроцессор, такой как Sass или Less, если вы хотите использовать таким образом. Если вы не используете его, вам просто нужно использовать эту линию фонового изображения для каждого цвета
— Дружественный код

36
Обратите внимание, что вы должны urlencode #символа для ваших шестнадцатеричных цветов, чтобы это работало в Firefox. Так что-то вроде <svg fill="#ffffff" ...></svg>становится <svg fill="%23ffffff" ...></svg>.
— Swen

1
Сладкий метод. Вы должны жестко закодировать SVG в фоновое изображение, как это? Можете ли вы просто не ссылаться на него как-нибудь?
— Люк

2
Я нашел этот сайт полезным для того, чтобы дать вам идеально закодированный URL, готовый к использованию: yoksel.github.io/url-encoder - просто скопируйте в него код SVG и скопируйте возвращенный CSS :-)
— Дружественный код

98

Вы можете использовать маски CSS. С помощью свойства 'mask' вы создаете маску, которая применяется к элементу.

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

Для получения дополнительной информации см. Эту замечательную статью: https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images


3
это хорошо, но при применении к значку в поле ввода весь вводимый текст скрыт.
— raison

14
Не поддерживается в IE
— Карим

Супер крутой ответ, но вы больше не можете использовать цвет фона при наведении или что-то в этом роде
— Пол Крюгер,

Похоже, что это вряд ли поддерживается - слишком много пользователей не смогут увидеть это, чтобы оно было жизнеспособным сегодня в конце 2018 года. Caniuse.com/#feat=css-masks
— Крис Москини

3
Лето 2019 года: 94% браузеров на этой планете поддерживают стили «mask-image» ИЛИ «-webkit-mask-image»
— Дмитрий Кулахин

57

Еще один подход заключается в использовании маски. Затем вы меняете цвет фона маскируемого элемента. Это имеет тот же эффект, что и изменение атрибута заполнения 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;
}

Вы найдете полное руководство здесь: http://codepen.io/noahblon/blog/coloring-svgs-in-css-background-images (не мое). Предлагает множество подходов (не ограничиваясь маской).


11
На это следует обратить внимание, это поддержка браузера. Я считаю, что IE (как обычно) сильно отстает в этом.
— Мэтью Джонсон

9
К сожалению mask, ни IE, ни Edge не поддерживаются: caniuse.com/#search=mask
— alpipego

В Chrome у меня тоже не работает. Изменить: О НВМ ... У меня не включен авторефикс. Я думал, что поставщики должны были прекратить использовать префиксы ?!
— mpen

Работает в последнем Chrome и Firefox
— тик

16

С Sass это возможно! Единственное, что вам нужно сделать, это кодировать URL-адрес вашего SVG-кода. И это возможно с помощью вспомогательной функции в Sass. Я сделал кодовую ручку для этого. Посмотри на это:

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
Это работает очень хорошо. Единственная проблема: в IE10 значок слишком маленький (я думаю, что 10% от заданного размера.
— Хеннинг Фишер,

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


1
Этот метод применяет фильтр ко всему объекту, включая детей.
— Кшиштоф

9

Загрузите свой svg как текст.

Измените текст SVG с помощью JavaScript, чтобы изменить цвет краски / обводки / заливки [s].

Затем вставьте измененную строку svg inline в ваш css, как описано здесь .


9

Теперь вы можете добиться этого на клиентской стороне следующим образом:

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

Скрипка здесь!


1
Вам следует избегать использования Base64 для SVG, так как это не нужно, увеличивает размер ваших файлов и даже не позволяет GZIP эффективно сжимать эти фрагменты кода.
— Инта

1
Эта кодировка происходит на стороне клиента, вероятно, только для полного выхода из
— строя

Само собой разумеется, что вы можете сделать что-нибудь с JS. Дело в том, чтобы избежать JS.
— MarsAndBack

7

Вы можете сохранить SVG в переменной. Затем управляйте строкой SVG в зависимости от ваших потребностей (например, установите ширину, высоту, цвет и т. Д.). Затем используйте результат для установки фона, например

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

Я тоже сделал демо, http://sassmeister.com/gist/4cf0265c5d0143a9e734 .

Этот код делает несколько предположений о SVG, например, у этого <svg />элемента нет существующего цвета заливки и что не заданы ни свойства ширины, ни высоты. Поскольку входные данные жестко закодированы в документе SCSS, эти ограничения довольно легко реализовать.

Не беспокойтесь о дублировании кода. сжатие делает разницу незначительной.


Дублирующий код - это запах кода, поэтому предлагать людям не беспокоиться о дублирующемся коде в случае вашего примера - не очень хорошая идея, однако, тем не менее, сказал, что я не вижу, где ваш код дублируется? Я думаю, что будет лучше, если вы просто удалите комментарий.
— профессор программирования

3

Вы можете создать свою собственную функцию SCSS для этого. Добавьте следующее в ваш файл 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

Тогда вы можете использовать его в своем CSS:

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

Вам нужно будет отредактировать SVG-файлы и заменить все атрибуты заливки в разметке на fill = "{color}"

Путь к значку всегда указывается относительно вашего параметра images_dir в том же файле config.rb.

Подобно некоторым другим решениям, но это довольно чисто и сохраняет ваши файлы SCSS аккуратными!


1
это из GitHub-вопроса . Просто
— ссылаюсь

2

В некоторых (очень специфических) ситуациях это может быть достигнуто с помощью фильтра . Например, вы можете изменить синее изображение SVG на фиолетовое, повернув оттенок на 45 градусов, используя filter: hue-rotate(45deg);. Поддержка браузера минимальна, но это все еще интересная техника.

демонстрация


2

для монохромного фона вы можете использовать SVG с маской, где должен отображаться цвет фона

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

и чем использовать этот CSS

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


1

Позже к показу здесь, НО, я смог добавить цвет заливки к многоугольнику SVG, если вы можете напрямую редактировать код SVG, например, следующий svg отображает красный цвет вместо черного по умолчанию. Я не тестировал за пределами 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

Это мой любимый метод, но поддержка вашего браузера должна быть очень прогрессивной. С помощью свойства mask вы создаете маску, которая применяется к элементу. Везде, где маска непрозрачна или сплошна, нижележащее изображение просвечивает. Там, где оно прозрачно, основное изображение скрыто или скрыто. Синтаксис CSS-маски-изображения аналогичен background-image. посмотри на кодеmask


-5

Много IF, но если ваш SVG в кодировке pre64 запустится:

<svg fill="#000000

Затем начнется закодированная строка base64:

PHN2ZyBmaWxsPSIjMDAwMDAw

если начинается предварительно закодированная строка:

<svg fill="#bfa76e

тогда это кодирует в:

PHN2ZyBmaWxsPSIjYmZhNzZl

Обе закодированные строки начинаются одинаково:

PHN2ZyBmaWxsPSIj

Причудой кодировки base64 является то, что каждые 3 входных символа становятся 4 выходными символами. Если SVG начинается следующим образом, то 6-символьный цвет заливки в шестнадцатеричном формате начинается точно с границы блока кодирования. Поэтому вы можете легко сделать кросс-браузерную замену JS:

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

Но ответ tnt-rox выше - это способ двигаться вперед.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.