Встроенный SVG в CSS

285

Можно ли использовать встроенное определение SVG в CSS?

Я имею в виду что-то вроде:

.my-class {
  background-image: <svg>...</svg>;
}
akaRem
источник
1
Что вы пытаетесь сделать, добавить изображение «источник» в таблицу стилей?
Зуул
1
Помните, что предложенные решения не будут работать с изображениями CSS, <img>тегами HTML и другими случаями, если SVG представляет собой сочетание нескольких изображений (если они не встроены), посмотрите фоновое изображение SVG с маской, использующей внешнее изображение , и конкретно ограничения на SVG, используемые как изображение .
Скиппи ле Гран Гуру

Ответы:

378

Да, это возможно. Попробуй это:

body { background-image: 
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='%23F00'/><stop offset='90%' stop-color='%23fcc'/> </linearGradient><rect fill='url(%23gradient)' x='0' y='0' width='100%' height='100%'/></svg>");
      }

(Обратите внимание, что контент SVG должен быть экранирован по URL, чтобы это работало, например, #заменяется на %23.)

Это работает в IE 9 (который поддерживает SVG) . URL-адреса данных также работают в более старых версиях IE (с ограничениями), но изначально не поддерживают SVG.

Рааб
источник
8
Единственный браузер, в котором он работает, это Safari (5.1.4). В Opera 11.62 градиент черный, в IE 9 и Firefox 12 - белый. В Chrome 19 это работает, если вы не укажете ширину / высоту SVG в%. Я бы сказал, что это скорее странность, чем реальная особенность. Это крутая находка.
toniedzwiedz
4
Правильно ... все же мне не терпится увидеть выражения лиц моих коллег, когда я показываю им такого милого маленького монстра, как этот, так что еще раз спасибо за показ, что это возможно. Я просто пошел к стандартной спецификации и заявил, что это практически невозможно, что оказалось ошибкой (вроде как)
toniedzwiedz
18
«Несовместимость браузера» здесь в основном заключается в отсутствии правильного экранирования URL, все внутри url()должно быть экранировано. См. Jsfiddle.net/6WAtQ для примера, который прекрасно работает в Opera, Firefox и Safari.
Эрик Дальстрем
3
Есть ли разница в совместимости между SV64 в кодировке SVG и не Base64? Base64 раздувает мой css файл, я думаю просто использовать встроенные svgs ..
enapupe
4
Обратите внимание, что стандартный способ указать набор символов - это «; charset = UTF-8» вместо «; utf8». tools.ietf.org/html/rfc2397
Кит Шоу,
240

Немного поздно, но если кто-то из вас сходит с ума, пытаясь использовать встроенный SVG в качестве фона , экранирующие предложения, приведенные выше, не совсем работают. С одной стороны, он не работает в IE, и в зависимости от содержимого вашего SVG методика вызовет проблемы в других браузерах, таких как FF.

Если вы base64 кодируете svg (не весь URL, а только тег svg и его содержимое!), Это работает во всех браузерах. Вот тот же пример jsfiddle в base64: http://jsfiddle.net/vPA9z/3/

CSS теперь выглядит так:

body { background-image: 
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PGxpbmVhckdyYWRpZW50IGlkPSdncmFkaWVudCc+PHN0b3Agb2Zmc2V0PScxMCUnIHN0b3AtY29sb3I9JyNGMDAnLz48c3RvcCBvZmZzZXQ9JzkwJScgc3RvcC1jb2xvcj0nI2ZjYycvPiA8L2xpbmVhckdyYWRpZW50PjxyZWN0IGZpbGw9J3VybCgjZ3JhZGllbnQpJyB4PScwJyB5PScwJyB3aWR0aD0nMTAwJScgaGVpZ2h0PScxMDAlJy8+PC9zdmc+");

Не забудьте удалить любой URL-адрес перед преобразованием в base64. Другими словами, в приведенном выше примере показано, что color = '# fcc' преобразовано в color = '% 23fcc', вы должны вернуться к #.

Причина, по которой base64 работает лучше, состоит в том, что он устраняет все проблемы с одинарными и двойными кавычками и экранированием URL

Если вы используете JS, вы можете использовать window.btoa()для создания вашего base64 svg; и если он не работает (он может жаловаться на недопустимые символы в строке), вы можете просто использовать https://www.base64encode.org/ .

Пример установки фона div:

var mySVG = "<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='#F00'/><stop offset='90%' stop-color='#fcc'/> </linearGradient><rect fill='url(#gradient)' x='0' y='0' width='100%' height='100%'/></svg>";
var mySVG64 = window.btoa(mySVG);
document.getElementById('myDiv').style.backgroundImage = "url('data:image/svg+xml;base64," + mySVG64 + "')";
html, body, #myDiv {
  width: 100%;
  height: 100%;
  margin: 0;
}
<div id="myDiv"></div>

С JS вы можете генерировать SVG на лету, даже изменяя его параметры.

Одна из лучших статей об использовании SVG находится здесь: http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

Надеюсь это поможет

Майк

Майк Томмаси
источник
2
Спасибо чувак. Решение с Base64 сработало отлично, а у меня возникли проблемы с принятым ответом.
Марсель
1
Вы спасли мою жизнь. У меня было изображение границы SVG, которое работало в Chrome, но не на FF. Теперь это работает! : D
Папипо
Мне также помогли (после потери времени, пробуя принятый ответ) - это определенно должен быть принятый ответ.
Катаи
Если это все еще не работает для вас - убедитесь, что у вас есть xmlnsатрибут, установленный для svgэлемента, прежде чем вы закодируете base64, как <svg xmlns="http://www.w3.org/2000/svg">...</svg>браузеры иногда разбивают его на части без него, когда svg находится непосредственно в HTML - это НЕ так :)
jave.web
Если кто-то еще ищет этот ответ 6+ лет спустя: вы, вероятно, не должны base64 SVGs css-tricks.com/probbly-dont-base64-svg
Volker E.
38

Для людей, которые все еще борются, мне удалось заставить это работать на всех современных браузерах IE11 и выше.

Base64 не был для меня вариантом, потому что я хотел использовать SASS для генерации SVG-иконок на основе любого заданного цвета. Например: @include svg_icon(heart, #FF0000);таким образом я могу создать определенную иконку любого цвета, и мне нужно только внедрить форму SVG в CSS. (с base64 вам нужно будет встраивать SVG в каждый цвет, который вы хотите использовать)

Есть три вещи, о которых вам нужно знать:

  1. URL ENCODE YOUR SVG Как уже предлагали другие, вам нужно URL кодировать всю строку SVG, чтобы она работала в IE11. В моем случае я пропустил значения цвета в таких полях, как fill="#00FF00"и, stroke="#FF0000"и заменил их на переменную SASS, fill="#{$color-rgb}"чтобы их можно было заменить на нужный мне цвет. Вы можете использовать любой онлайн-конвертер, чтобы URL кодировал остальную часть строки. В итоге вы получите строку SVG:

    % 3Csvg% 20xmlns% 3D% 27http% 3A% 2F% 2Fwww.w3.org% 2F2000% 2Fsvg% 27% 20viewBox% 3D% 270% 200% 20494,572% 20494,572% 27% 20width% 3D% 27512% 27% 20height% 3D % 27512% 27% 3E% 0A% 20% 20% 3Cpath% 20d% 3D% 27M257.063% 200C127.136% 200% 2021,808% 20105,33% 2021,808% 20235.266c0% 2041,012% 2010,535% 2079,541% 2028,973% 20113.104L3.825 % 20464.586c345% 2012.797% 2041.813% 2012.797% 2015.467% 200% 2029.872-4.721% 2041.813-12.797v158.184z% 27% 20fill% 3D% 27 # {$ color-rgb} % 27% 2F% 3E% 3C% 2Fsvg% 3E


  1. ПУТЕШЕСТВУЙТЕ CHARSET UTF8 В URL-адресе данных. При создании URL-адреса данных необходимо не использовать кодировку, чтобы он работал в IE11.

    НЕ фоновое изображение: url (данные: image / svg + xml; utf-8,% 3Csvg% 2 ....)
    НО фоновое изображение: url (данные: image / svg + xml,% 3Csvg% 2 ... .)


  1. ИСПОЛЬЗУЙТЕ RGB () ВМЕСТО цветов HEX Firefox не любит # в коде SVG. Так что вам нужно заменить значения цвета в шестнадцатеричном формате на RGB.

    NOT fill = "# FF0000",
    НО fill = "rgb (255,0,0)"

В моем случае я использую SASS для преобразования данного гекса в действительное значение RGB. Как указано в комментариях, лучше всего URL-кодировать и вашу строку RGB (так что запятая становится% 2C)

@mixin svg_icon($id, $color) {
   $color-rgb: "rgb(" + red($color) + "%2C" + green($color) + "%2C" + blue($color) + ")";
   @if $id == heart {
      background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20494.572%20494.572%27%20width%3D%27512%27%20height%3D%27512%27%3E%0A%20%20%3Cpath%20d%3D%27M257.063%200C127.136%200%2021.808%20105.33%2021.808%20235.266c0%204%27%20fill%3D%27#{$color-rgb}%27%2F%3E%3C%2Fsvg%3E');
   }
}

Я понимаю, что это может быть не лучшим решением для очень сложных SVG (встроенный SVG в этом случае никогда не бывает), но для плоских значков с несколькими цветами это действительно отлично работает.

Мне удалось опустить весь растровый рисунок спрайта и заменить его встроенным SVG в моем CSS, который оказался только около 25 КБ после сжатия. Так что это отличный способ ограничить количество запросов, которые должен выполнять ваш сайт, без раздувания вашего CSS-файла.

Дэви Баерт
источник
1
Кстати, поправьте меня, если я ошибаюсь, но rgb(255,0,0)должен стать rgb(255%2C0%2C0)однажды закодированным.
Капсула
1
Я имел в виду, что я не кодирую строку RGB, и она все еще работает. Но кодирование, как вы упомянули, возможно, лучше.
Дэви Бэрт
1
Ну, на самом деле, я только что проверил и %23ff0000отлично работает #ff0000в Firefox
Capsule
1
@ Капсула Я не знаю, что происходит, но% 23ff0000 - ЕДИНСТВЕННЫЙ метод, который работает для меня как на Chrome, так и на FF. # ff0000 не работает, равно как и методы RGB (255,0,0) и rgb (255% 2C0% 2C0).
Идеограмма
1
Метод (включая код SCSS), который требует меньшего количества кодирования: codepen.io/jakob-e/pen/doMoML
Sphinxxx
26

В Mac / Linux вы можете легко преобразовать файл SVG в закодированное в base64 значение для атрибута фона CSS с помощью этой простой команды bash:

echo "background: transparent url('data:image/svg+xml;base64,"$(openssl base64 < path/to/file.svg)"') no-repeat center center;"

Протестировано на Mac OS X. Таким образом вы также избежите путаницы с URL.

Помните, что base64-кодировка SVG-файла увеличивает его размер, см. Сообщение в блоге css-tricks.com .

Аракс
источник
2
Читателям: пожалуйста, прокомментируйте свое мнение, а не просто проголосуйте, чтобы этот ответ можно было улучшить с вашим сотрудничеством! Сотрудничество на сайтах вопросов и ответов очень важно. Спасибо!
Аракс
2
@LorDex ссылка, которую вы указали в своем комментарии, такая же, как и в моем ответе :)
araks
10

Я разработал демонстрационную версию CodePen, у которой была та же проблема со встроенным SVG в CSS. Решение, которое работает с SCSS, заключается в создании простой функции кодирования URL.

Функция замены строки может быть создана из встроенных функций str-slice, str-index (см. Трюки css , благодаря Hugo Giraudel).

Тогда, просто заменить %, <, >, ", ', с %xxкодами:

@function svg-inline($string){
  $result: str-replace($string, "<svg", "<svg xmlns='http://www.w3.org/2000/svg'");
  $result: str-replace($result, '%', '%25');
  $result: str-replace($result, '"', '%22');
  $result: str-replace($result, "'", '%27');
  $result: str-replace($result, ' ', '%20');
  $result: str-replace($result, '<', '%3C');
  $result: str-replace($result, '>', '%3E');
  @return "data:image/svg+xml;utf8," + $result;
}

$mySVG: svg-inline("<svg>...</svg>");

html {
  height: 100vh;
  background: url($mySVG) 50% no-repeat;
}

В image-inlineCompass также доступна вспомогательная функция, но, поскольку она не поддерживается в CodePen, это решение может быть полезным.

Демонстрация на CodePen: http://codepen.io/terabaud/details/PZdaJo/

Леа Розема
источник
1
Я также создал перо, которое позволяет вам конвертировать строки svg в правильное фоновое значение css: s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb Итак, в основном, вы вставляете ваш текст<svg><path></svg> в верхнюю текстовую область, и он напрямую выводит очищенный путь в пределах url()значения.
LukyVj
1
Это сработало потрясающе. Спасибо. Одна запись. Вам нужно использовать; charset = utf8, чтобы заставить это работать в IE.
Даниэль Лефевр
4

Встроенный SVG, поступающий из сторонних источников (таких как диаграммы Google), может не содержать атрибута пространства имен XML ( xmlns="http://www.w3.org/2000/svg") в элементе SVG (или, возможно, он удаляется после визуализации SVG - ни инспектор браузера, ни команды jQuery из консоли браузера не показывают пространство имен в элементе SVG).

Когда вам нужно переопределить эти фрагменты svg для других ваших нужд (background-image в CSS или элемент img в HTML), следите за отсутствующим пространством имен. Без пространства имен браузеры могут отказаться отображать SVG (независимо от кодировки utf8 или base64).

mp31415
источник
4

Я нашел одно решение для SVG. Но это работа только для Webkit, я просто хочу поделиться с вами своим обходным путем. В моем примере показано, как использовать элемент SVG из DOM в качестве фона через фильтр (background-image: url ('# glyph') не работает).

Функции, необходимые для визуализации иконки SVG:

  1. Применение эффектов фильтра SVG к элементам HTML с использованием CSS (IE и Edge не поддерживаются)
  2. Поддержка загрузки фрагмента feImage (Firefox не поддерживает)

.test {
  /*  background-image: url('#glyph');
    background-size:100% 100%;*/
    filter: url(#image); 
    height:100px;
    width:100px;
}
.test:before {
   display:block;
   content:'';
   color:transparent;
}
.test2{
  width:100px;
  height:100px;
}
.test2:before {
   display:block;
   content:'';
   color:transparent;
   filter: url(#image); 
   height:100px;
   width:100px;
}
<svg style="height:0;width:0;" version="1.1" viewbox="0 0 100 100"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
 <defs>
     <g id="glyph">
          <path id="heart" d="M100 34.976c0 8.434-3.635 16.019-9.423 21.274h0.048l-31.25 31.25c-3.125 3.125-6.25 6.25-9.375 6.25s-6.25-3.125-9.375-6.25l-31.202-31.25c-5.788-5.255-9.423-12.84-9.423-21.274 0-15.865 12.861-28.726 28.726-28.726 8.434 0 16.019 3.635 21.274 9.423 5.255-5.788 12.84-9.423 21.274-9.423 15.865 0 28.726 12.861 28.726 28.726z" fill="crimson"/>
     </g>
    <svg id="resized-glyph"  x="0%" y="0%" width="24" height="24" viewBox="0 0 100 100" class="icon shape-codepen">
      <use xlink:href="#glyph"></use>
    </svg>
     <filter id="image">
       <feImage xlink:href="#resized-glyph" x="0%" y="0%" width="100%" height="100%" result="res"/>
       <feComposite operator="over" in="res" in2="SourceGraphic"/>
    </filter>
 </defs>
</svg>
<div class="test">
</div>
<div class="test2">
</div>

Еще одно решение - использовать url encode

var container = document.querySelector(".container");
var svg = document.querySelector("svg");
var svgText = (new XMLSerializer()).serializeToString(svg);
container.style.backgroundImage = `url(data:image/svg+xml;utf8,${encodeURIComponent(svgText)})`;
.container{
  height:50px;
  width:250px;
  display:block;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: contain;
}
<svg  height="100" width="500" xmlns="http://www.w3.org/2000/svg">
    <ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" />
</svg>
<div class="container"></div>

Алекс Никулин
источник