Как стилизовать SVG с помощью внешнего CSS?

102

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

Я реализовал их таким образом, чтобы всплывающие подсказки работали, и я также заключил каждый в <a>тег, чтобы разрешить ссылку.

<a href='http://youtube.com/...' target='_blank'><img class='socIcon' src='images/socYouTube.svg' title='View my videos on YouTube' alt='YouTube' /></a>

А вот код изображения SVG:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="stylesheets/main.css" type="text/css"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
<g>
    <path d="M28.44......./>
</g>
</svg>

Я помещаю в свой внешний файл CSS (main.css) следующее:

.socIcon g {fill:red;}

Тем не менее, это не влияет на графику. Я также пробовал .socIcon g path {} и .socIcon path {}.

Что-то не так, возможно, моя реализация не допускает внешних модификаций CSS, или я пропустил шаг? Буду очень признателен за вашу помощь! Мне просто нужна возможность изменять цвета графики SVG через мою внешнюю таблицу стилей, но я не могу потерять всплывающую подсказку и возможность ссылки. (Хотя, возможно, я смогу жить без всплывающих подсказок.) Спасибо!

Jordan H
источник
См. Stackoverflow.com/questions/12604095/…
Эрик Дальстрем
Попробуйте svg { fill:red; }или дайте своему пути имя класса. Например, <path class="socIcon" d="M28.44 ..... />это должно помочь.
Dwza 05

Ответы:

92

Ваш файл main.css будет влиять на содержимое SVG только в том случае, если файл SVG встроен в HTML:

https://developer.mozilla.org/en/docs/SVG_In_HTML_Introduction

<html>
  <body>
  <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
    <g>
      <path d="M28.44......./>
    </g>
  </svg>
</html>

Если вы хотите сохранить свой SVG в файлах, CSS необходимо определить внутри файла SVG.

Вы можете сделать это с помощью тега стиля:

http://www.w3.org/TR/SVG/styling.html#StyleElementExample

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
     width="50px" height="50px" viewBox="0 0 50 50">
  <defs>
    <style type="text/css"><![CDATA[
      .socIcon g {
        fill:red;
      }
    ]]></style>
  </defs>
  <g>
    <path d="M28.44......./>
  </g>
</svg>

Вы можете использовать инструмент на стороне сервера для обновления тега стиля в зависимости от активного стиля. В рубине этого можно добиться с помощью Nokogiri. SVG - это просто XML. Так что, вероятно, существует множество доступных XML-библиотек, которые, вероятно, могут достичь этого.

Если вы не можете этого сделать, вам просто придется использовать их, как если бы они были PNG; создание набора для каждого стиля и встроенное сохранение их стилей.

RGB
источник
17
Означает ли это, что нет способа извлечь выгоду из кеширования SVG и применения различных стилей? Inline, похоже, плохо кеширует, в то время как другие методы потребуют создания многих версий изображения, что исключает какую-либо выгоду от их кеширования.
msg45f 06
Другой способ - закодировать SVG как uris данных фонового изображения, с разными цветами для каждой версии и полагаться на gzip для уменьшения размера файла из-за дублирования.
Раскин
1
В моем случае я хотел переопределить стили элементов из SVG. Мой CSS не работал, потому что стили элементов имели более высокий приоритет. Самым простым решением было добавить! Important в стиль CSS для SVG. Тогда все было хорошо. Если вы хотите избежать! Important, вам нужно переместить стили элементов в CSS.
Дэвид Гаусманн,
жаль, что вы не можете загрузить таблицу стилей в svg с URL-адреса
ClayRay
1
@clayRay, вы сможете сделать это таким образом, как только SVG2 будет завершен черновик w3.org/TR/SVG2/styling.html#LinkElement
RGB
51

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

В вашем html-файле вам нужно что-то вроде этого:

<style>
  .fill-red { fill: red; }
  .fill-blue { fill: blue; }
</style>

<a href="//www.example.com/">
  <svg class="fill-red">
    <use xlink:href="images/icons.svg#example"></use>
  </svg>
</a>

А во внешнем файле SVG вы хотите что-то вроде этого:

<svg xmlns="http://www.w3.org/2000/svg">
   <symbol id="example" viewBox="0 0 256 256">
    <path d="M120.... />
  </symbol>
</svg>

Поменяйте местами класс в svgтеге (в вашем html) с fill-redна fill-blueи ta-da ... у вас синий вместо красного.

Вы можете частично обойти ограничение возможности настраивать пути по отдельности с помощью внешнего CSS, смешивая и сопоставляя внешний CSS с некоторым встроенным CSS на определенных путях, поскольку встроенный CSS будет иметь приоритет. Этот подход будет работать, если вы делаете что-то вроде белого значка на цветном фоне, где вы хотите изменить цвет фона с помощью внешнего CSS, но сам значок всегда белый (или наоборот). Итак, с тем же HTML, что и раньше, и чем-то вроде этого кода svg, вы получите красный фон и белый путь переднего плана:

<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="example" viewBox="0 0 256 256">
    <path class="background" d="M120..." />
    <path class="icon" style="fill: white;" d="M20..." />
  </symbol>
</svg>
Адам Корман
источник
хороший ответ .. я думаю, что предостережение действительно должно быть: хотя поддержка браузера! хорошая ссылка (более подробно, чем caniuse): css-tricks.com/svg-fragment-identifiers-work
ptim
Это решение! На самом деле нет необходимости оборачивать все содержимое svg в symbolэлементе, т.е. вы можете просто idуказать элемент svg, поэтому: `<svg id = example" xmlns = " w3.org/2000/svg " viewBox = "0 0 256 256 "> <path class =" background "d =" M120 ... "/> <path class =" icon "style =" fill: white; "d =" M20 ... "/> </ svg > `
SimoneMSR
12

Вы можете включить в свои файлы SVG ссылку на внешний файл css, используя:

<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="mystyles.css" type="text/css"/>

Вам нужно поставить это после открывающего тега:

<svg>
  <link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="mystyles.css" type="text/css"/>
  <g>
    <path d=.../>
  </g>
</svg>

Это не идеальное решение, потому что вам нужно изменить файлы svg, но вы изменяете их один раз, и тогда все изменения стиля могут быть выполнены в одном файле css для всех файлов svg.

Яцек Мамот
источник
1
Вау, это работает, но только 1 голос за ... подходит ли это решение для всех ситуаций? Это так просто, почему не выбран этот ответ?
Бруно Винсент,
Все дело в централизации ваших определений стиля. Допустим, у вас есть 10 SVG, которые вы хотите стилизовать. Теперь вам нужно скопировать ссылку на CSS во все SVG, которые нужно изменить. И если имя файла / расположение вашего CSS изменится, вам необходимо обновить его в 10 SVG. Класс CSS кажется намного более символичным, чем ссылка на физический файл CSS.
Франс,
Обратите внимание, что svg, загруженный с помощью тега <img>, не будет загружать внешний контент (например, таблицы стилей).
Moose Morals
7

Можно стилизовать SVG, динамически создав элемент стиля в JavaScript и добавив его к элементу SVG. Хакерский, но работает.

<object id="dynamic-svg" type="image/svg+xml" data="your-svg.svg">
    Your browser does not support SVG
</object>
<script>
    var svgHolder = document.querySelector('object#dynamic-svg');
    svgHolder.onload = function () {
        var svgDocument = svgHolder.contentDocument;
        var style = svgDocument.createElementNS("http://www.w3.org/2000/svg", "style");

        // Now (ab)use the @import directive to load make the browser load our css
        style.textContent = '@import url("/css/your-dynamic-css.css");';

        var svgElem = svgDocument.querySelector('svg');
        svgElem.insertBefore(style, svgElem.firstChild);
    };
</script>

Вы можете динамически генерировать JavaScript в PHP, если хотите - тот факт, что это возможно в JavaScript, открывает множество возможностей.

Пит
источник
эй, мне действительно нравится ваше решение, и оно работает, но мне нужно принять его в моей ситуации, если вы хотите помочь, конечно, у меня внутри <defs> тег стиля, я могу удалить их вручную и запустить этот код, чтобы он создал стиль, есть ли способ удалить defs, а затем воссоздать элемент, как вы, или просто обновить его, а также URL-адрес получил ошибку URL-адрес не определен, не могли бы вы помочь, спасибо
Камель Мили
6

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

Например, если у вас есть SVG-графика, которая использует красный цвет заливки в SVG-коде, вы можете сделать ее фиолетовой с настройкой поворота оттенка на 180 градусов:

#theIdOfTheImgTagWithTheSVGInIt {
    filter: hue-rotate(180deg);
    -webkit-filter: hue-rotate(180deg);
    -moz-filter: hue-rotate(180deg);
    -o-filter: hue-rotate(180deg);
    -ms-filter: hue-rotate(180deg);
}

Поэкспериментируйте с другими настройками поворота оттенка, чтобы найти нужные цвета.

Чтобы было ясно, приведенный выше CSS входит в CSS, который применяется к вашему HTML-документу. Вы задаете стиль тега img в HTML-коде, а не стилизуете код SVG.

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

Саймон Уайт
источник
4

Очень быстрое решение для динамического стиля с внешней таблицей стилей CSS, если вы используете <object> тег для встраивания своего svg.

Этот пример добавит класс к корневому <svg>тегу при щелчке по родительскому элементу.

file.svg:

<?xml-stylesheet type="text/css" href="../svg.css"?>
 <svg xmlns="http://www.w3.org/2000/svg" viewBox="">
  <g>
   <path/>
  </g>
 </svg>

html:

<a class="parent">
  <object data="file.svg"></object>
</a>

JQuery:

$(function() {
  $(document).on('click', '.parent', function(){
    $(this).find('object').contents().find('svg').attr("class","selected");
  }
});

при щелчке по родительскому элементу:

 <svg xmlns="http://www.w3.org/2000/svg" viewBox="" class="selected">

тогда вы можете управлять своим css

svg.css:

path {
 fill:none;
 stroke:#000;
 stroke-miterlimit:1.41;
 stroke-width:0.7px;
}

.selected path {
 fill:none;
 stroke:rgb(64, 136, 209);
 stroke-miterlimit:1.41;
 stroke-width:0.7px;
}
Vhanahrni
источник
не работает, не могли бы вы добавить рабочий пример?
Jeanluca Scaljeri
4

Это должно быть возможно сделать, сначала встраивая внешние изображения svg. Приведенный ниже код взят из замены всех изображений SVG встроенным SVG Джессом Фразелл.

$('img.svg').each(function(){
  var $img = $(this);
  var imgID = $img.attr('id');
  var imgClass = $img.attr('class');
  var imgURL = $img.attr('src');
  $.get(imgURL, function(data) {
    // Get the SVG tag, ignore the rest
    var $svg = $(data).find('svg');
    // Add replaced image's ID to the new SVG
    if (typeof imgID !== 'undefined') {
      $svg = $svg.attr('id', imgID);
    }
    // Add replaced image's classes to the new SVG
    if (typeof imgClass !== 'undefined') {
      $svg = $svg.attr('class', imgClass+' replaced-svg');
    }
    // Remove any invalid XML tags as per http:validator.w3.org
    $svg = $svg.removeAttr('xmlns:a');
    // Replace image with new SVG
    $img.replaceWith($svg);
  });
});
Лео
источник
3
Важно отметить, что это будет работать только в том случае, если у вас есть изображение, размещенное в том же домене, что и html, или у вас есть специально настроенная междоменная политика на сервере изображений. $ .get будет использовать ajax и не сможет загрузить изображение с внешнего сервера, если нет допустимого заголовка allow-access
user151496
это легендарно
Тино Коста 'Эль-Ниньо'
2

При использовании в <image>теге SVG должен содержаться в одном файле по соображениям конфиденциальности. Эта ошибка bugzilla содержит более подробную информацию о том, почему это так. К сожалению, вы не можете использовать другой тег, например<iframe> потому что он не будет работать как ссылка, поэтому вам придется вставлять CSS в<style> тег внутри самого файла.

Еще один способ сделать это - разместить данные SVG в основном файле html, т.е.

<a href='http://youtube.com/...' target='_blank'>
  <svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
    <g>
        <path d="M28.44......./>
    </g>
  </svg>
</a>

Вы можете стилизовать это с помощью внешнего файла CSS, используя <link>тег HTML .

Роберт Лонгсон
источник
2
Я не могу поместить стили в файлы. На самом деле я собираюсь изменить цвета этих изображений в зависимости от цветовой схемы, выбранной пользователем для моего сайта. Моя текущая реализация - добавить на главную страницу таблицу стилей, которая перезаписывает стили по умолчанию. Я хотел внести изменения цвета в этот файл, чтобы повлиять на встроенную графику SVG. Но это не сработает, потому что мне нужно связать таблицу стилей из файла SVG (если нет способа добавить эту ссылку ко всем файлам SVG с помощью JavaScript). Конечно, есть способ разрешить внешние файлы SVG, внешний CSS, ссылки и всплывающие подсказки.
Jordan H
1
Невозможно делать то, что вы хотите, из-за модели безопасности браузера. Вы не можете использовать javascript для управления SVG, когда он используется в качестве изображения. Думайте о SVG, когда он используется как изображение, как о анимированном файле png или gif, все в одном файле и без доступа к сценариям.
Роберт Лонгсон,
1

«На самом деле я собираюсь изменить цвета этих изображений в зависимости от того, какую цветовую схему выбрал пользователь для моего сайта». - Иордания 10 часов назад

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

<?php

    header('Content-Type: image/svg+xml');
    echo '<?xml version="1.0" encoding="utf-8"?>';
    $color = $_GET['color'];

?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
    <g>
        <path fill="<?php echo $color; ?>" d="M28.44..."/>
    </g>
</svg>

А позже вы можете использовать этот файл, filename.php?color=#ffffffчтобы получить файл svg желаемого цвета.

SeinopSys
источник
7
Обратите внимание, что этот код не проверяет ввод данных пользователем - все может быть предоставлено в виде цвета, и ваш SVG может быть отображен очень интересными способами ... Не уверен, влияет ли это на вас, но вы должны сделать привычкой ВСЕГДА проверять вводимые пользователем данные. Что-то вроде этого могло бы помочь: if (!preg_match('/^[#][0-9a-f]{6}$/i', $_GET['color'])) die('Oops!');(поместите его где-нибудь в начальный блок PHP).
johndodo
1

Что мне подходит: тег стиля с правилом @import

<defs>
    <style type="text/css">
        @import url("svg-common.css");
    </style>
</defs>
Fordi
источник
1

Я знаю, что это старый пост, но просто чтобы решить эту проблему ... вы просто используете свои классы не в том месте: D

Прежде всего вы можете использовать

svg { fill: red; }

в твоем, main.cssчтобы он стал красным. Это имеет эффект. Возможно, вы также можете использовать селекторы узлов, чтобы получить определенные пути.

Во-вторых, вы объявили класс в img-Tag.

<img class='socIcon'....

На самом деле вы должны объявить это внутри своего SVG. если у вас есть разные пути, вы, конечно, можете определить больше.

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="stylesheets/main.css" type="text/css"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
<g>
    <path class="myClassForMyPath" d="M28.44......./>
</g>
</svg>

теперь вы можете изменить цвет на свой main.cssвкус

.myClassForMyPath {
    fill: yellow;
}
Dwza
источник
Пробовал, это не работает, как уже говорят многие другие ответы. Вы не можете применять стили к классам внутри SVG.
Франс,
@Frans, включаете ли вы svg как файл или у вас есть исходный код svg, как в примере выше? Потому что я имею в виду, что это зависит от того, как вы используете svg. В том числе по img работать не будет.
Dwza
Точно, это работает, только если вы встраиваете SVG в свой HTML. Но это не то, что делает ваш пример. Он использует внешний (т.е. не встроенный) SVG. Кажется, нет способа стилизовать внешний SVG с помощью CSS в вашем HTML.
Франс
уверен, что вы правильно пробовали мой пример? я имею в виду, включил файл css из внешнего? <?xml-stylesheet href="stylesheets/main.css" type="text/css"?>
Dwza,
Хорошо, теперь я вижу, у вас есть <?xml-stylesheet ... ?>объявление внутри вашего SVG. Думаю, это сработает. Это похоже на другие ответы, рекомендующие <link rel="stylesheet" ... >внутри SVG. У него также есть те же проблемы (вам необходимо обновить каждый SVG, чтобы он указывал на таблицу стилей, и любое изменение имени или местоположения таблицы стилей означает необходимость снова изменить все SVG).
Франс,
1
  1. Для внешних стилей

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">

  <style>
	@import url(main.css);
  </style>

  <g>
    <path d="M28.44......./>
  </g>
</svg>

  1. Для внутренних стилей

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">

  <style>
	    .socIcon g {fill:red;}
  </style>

  <g>
    <path d="M28.44......./>
  </g>
</svg>

Примечание. Внешние стили не будут работать, если вы включите SVG внутри <img>тега. Он будет отлично работать внутри <div>тега

Юврай Патил
источник
0

@leo вот версия angularJS, еще раз спасибо

G.directive ( 'imgInlineSvg', function () {

return {
    restrict : 'C',
    scope : true,
    link : function ( scope, elem, attrs ) {

        if ( attrs.src ) {

            $ ( attrs ).each ( function () {
                var imgID    = attrs.class;
                var imgClass = attrs.class;
                var imgURL   = attrs.src;

                $.get ( imgURL, function ( data ) {

                    var $svg = $ ( data ).find ( 'svg' );
                    if ( typeof imgID !== 'undefined' ) {
                        $svg = $svg.attr ( 'id', imgID );
                    }

                    if ( typeof imgClass !== 'undefined' ) {
                        $svg = $svg.attr ( 'class', imgClass + ' replaced-svg' );
                    }

                    $svg = $svg.removeAttr ( 'xmlns:a' );

                    elem.replaceWith ( $svg );

                } );

            } );
        }

    }

}

} );
Тино Коста 'Эль-Ниньо'
источник
-1

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

HTMLGUY1999
источник