Змініть колір заповнення 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'); ?>
Сол Фотлі,

4
Ви можете використовувати зображення svg як маску та маніпулювати кольором фону. Це матиме такий же ефект, як і зміна заливки. (детальна відповідь надана)
розширений

16
Ця відповідь була чудовою станом на 2012 рік, але зараз CSS-маски та / або фільтри вже деякий час підтримуються у всіх браузерах. Я рекомендую всім, хто читає це, перевірити посилання у відповіді віджетів нижче або просто перейти сюди до CSS Masks , що є дуже простим рішенням - зауважте, що для цього все ж потрібна 2 версії правила, одна з приставкою -webkit- в даний час час. Для Microsoft Edge в даний час підтримуються фільтри CSS, але ще не маски.
joelhardi

2
Нижче наведено багато рішень, які працюють сьогодні, я згоден, ця відповідь більше не відображає поточний стан можливостей.
Девід Нето

148

Мені потрібно було щось подібне і хотів дотримуватися CSS. Ось менші та 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, якщо ви хочете використовувати цей спосіб. Якщо ви не використовуєте його, вам просто потрібно буде використовувати цю лінію-зображення для кожного кольору
Friendly Code

36
Зауважте, що ви повинні urlencode #символу для ваших шестигранних кольорів, щоб зробити цю роботу в Firefox. Так щось на кшталт <svg fill="#ffffff" ...></svg>стає <svg fill="%23ffffff" ...></svg>.
Swen

1
Солодкий метод. Вам доводиться жорстко кодувати svg у фоновому зображенні? Ви не можете просто так якось зв’язатись із цим?
luke

2
Я вважаю цей сайт корисним для надання вам ідеально закодованої URL-адреси, готової до використання: yoksel.github.io/url-encoder - Просто скопіюйте у нього SVG-код та скопіюйте повернений CSS :-)
Friendly Code

94

Ви можете використовувати маски 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
Kareem

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

Це, здається, ледве підтримується, якщо взагалі - занадто багато користувачів не змогли б побачити, що це стане життєздатним сьогодні наприкінці 2018 року. Caniuse.com/#feat=css-masks
Кріс Москіні

3
Літо 2019: 94% браузерів на цій планеті підтримують стилі "mask-image" OR "-webkit-mask-image"
Дмитро Кулахін

57

Ще один підхід - використовувати маску. Потім ви змінюєте колір фону маскуваного елемента. Це має той же ефект, що і зміна атрибуту fill 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. Редагувати: О, nvm ... У мене не ввімкнено автоматичний виправлення. Я думав, що продавці повинні припинити використання префіксів ?!
1717 року

Працює в останній хром і
тик

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 . Просто посилаючись на це, якщо хтось захоче прочитати там дискусію
MMachinegun

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

Це мій улюблений метод, але підтримка вашого браузера повинна бути дуже прогресивною. За допомогою властивості маски ви створюєте маску, яка застосовується до елемента. Скрізь, де маска непрозора або суцільна, основне зображення видно наскрізь. Там, де воно прозоре, основне зображення замасковане або приховане. Синтаксис CSS-маски-зображення схожий на фонове зображення. подивіться на кошикmask


-5

Дуже багато IF, але якщо SVG запускає попередньо base64:

<svg fill="#000000

Тоді запуститься кодований рядок base64:

PHN2ZyBmaWxsPSIjMDAwMDAw

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

<svg fill="#bfa76e

то це кодує до:

PHN2ZyBmaWxsPSIjYmZhNzZl

Обидва закодовані рядки починаються однаково:

PHN2ZyBmaWxsPSIj

Вигадка кодування base64 - це кожні 3 вхідні символи стають 4 вихідними символами. Якщо SVG починається так, то 6-символьний колір шістнадцяткового заповнення починається саме на "межі" блоку кодування. Тому ви можете легко зробити заміну JS-крос-браузера:

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

Але відповідь тнт-рокс вище - це спосіб рухатися вперед.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.