Jak stylizować SVG za pomocą zewnętrznego CSS?

102

Mam kilka grafik SVG, które chciałbym zmodyfikować za pomocą moich zewnętrznych arkuszy stylów - nie bezpośrednio w każdym pliku SVG. Nie umieszczam grafik w jednej linii, ale przechowuję je w folderze z obrazami i wskazuję na nie.

Zaimplementowałem je w ten sposób, aby umożliwić działanie podpowiedzi, a także zawinąłem każdą w <a>tag, aby umożliwić link.

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

A oto kod grafiki 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>

W moim zewnętrznym pliku CSS (main.css) umieściłem:

.socIcon g {fill:red;}

Jednak nie ma to wpływu na grafikę. Próbowałem też .socIcon g path {} i .socIcon path {}.

Coś jest nie tak, być może moja implementacja nie pozwala na zewnętrzne modyfikacje CSS lub przegapiłem krok? Byłbym wdzięczny za twoją pomoc! Potrzebuję tylko możliwości modyfikowania kolorów grafiki SVG za pomocą mojego zewnętrznego arkusza stylów, ale nie mogę stracić podpowiedzi i możliwości linków. (Mogę żyć bez podpowiedzi.) Dzięki!

Jordan H.
źródło
Spróbuj svg { fill:red; }lub nadaj swojej ścieżce nazwę klasy. Np. <path class="socIcon" d="M28.44 ..... />To powinno załatwić sprawę.
Dwza

Odpowiedzi:

92

Twój plik main.css miałby wpływ na zawartość SVG tylko wtedy, gdy plik SVG jest zawarty w kodzie 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>

Jeśli chcesz zachować swój SVG w plikach, CSS musi być zdefiniowany w pliku SVG.

Możesz to zrobić za pomocą tagu stylu:

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>

Możesz użyć narzędzia po stronie serwera, aby zaktualizować tag stylu w zależności od aktywnego stylu. W rubinie można to osiągnąć z Nokogiri. SVG to po prostu XML. Więc prawdopodobnie istnieje wiele dostępnych bibliotek XML, które prawdopodobnie mogą to osiągnąć.

Jeśli nie jesteś w stanie tego zrobić, będziesz musiał po prostu używać ich tak, jakby były plikami PNG; tworzenie zestawu dla każdego stylu i zapisywanie ich stylów bezpośrednio.

RGB
źródło
17
Czy to oznacza, że ​​nie ma metody, aby skorzystać z buforowania SVG i stosowania różnych stylów? Inline nie wydaje się dobrze buforować, podczas gdy inne metody wymagałyby tworzenia wielu wersji obrazu, eliminując wszelkie korzyści z ich buforowania.
msg45f
Innym sposobem jest zakodowanie plików SVG jako danych obrazu tła, z różnymi kolorami w każdej wersji i skorzystanie z programu gzip w celu zmniejszenia rozmiaru pliku z powodu duplikacji.
Ruskin
1
W moim przypadku chciałem nadpisać style elementów z SVG. Mój CSS nie działał, ponieważ style elementów miały wyższy priorytet. Najprostszym rozwiązaniem było dodanie! Ważnego do stylu CSS SVG. Wtedy wszystko było w porządku. Jeśli chcesz tego uniknąć, ważne, musisz przenieść style elementów do CSS.
David Gausmann
szkoda, że ​​nie możesz załadować arkusza stylów do pliku svg z adresu URL
clayRay
1
@clayRay będziesz mógł to zrobić w ten sposób, gdy SVG2 będzie kompletny. szkic w3.org/TR/SVG2/styling.html#LinkElement
RGB
51

Możesz robić, co chcesz, z jednym (ważnym) zastrzeżeniem: ścieżki w Twoim symbolu nie mogą być stylizowane niezależnie przez zewnętrzny CSS - możesz ustawić właściwości tylko dla całego symbolu za pomocą tej metody. Tak więc, jeśli masz dwie ścieżki w swoim symbolu i chcesz, aby miały różne kolory wypełnienia, to nie zadziała, ale jeśli chcesz, aby wszystkie ścieżki były takie same, powinno to działać.

W swoim pliku html chcesz coś takiego:

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

A w zewnętrznym pliku SVG chcesz coś takiego:

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

Zamień klasę na svgtagu (w swoim html) z fill-reddo fill-bluei ta-da ... masz niebieski zamiast czerwonego.

Możesz częściowo obejść ograniczenie możliwości kierowania ścieżek oddzielnie za pomocą zewnętrznego CSS, mieszając i dopasowując zewnętrzny CSS do niektórych wbudowanych CSS na określonych ścieżkach, ponieważ wbudowany CSS będzie miał pierwszeństwo. To podejście zadziała, jeśli robisz coś w rodzaju białej ikony na kolorowym tle, gdzie chcesz zmienić kolor tła za pomocą zewnętrznego CSS, ale sama ikona jest zawsze biała (lub odwrotnie). Tak więc, z tym samym kodem HTML co poprzednio i czymś w rodzaju tego kodu SVG, otrzymasz czerwone tło i białą ścieżkę pierwszego planu:

<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>
Adam Korman
źródło
dobra odpowiedź ... myślę, że zastrzeżenie powinno brzmieć: chociaż obsługa przeglądarek! dobre odniesienie (więcej szczegółów niż caniuse): css-tricks.com/svg-fragment-identifiers-work
ptim
To jest rozwiązanie! Właściwie nie ma potrzeby zawijania całej zawartości svg w symbolelement, tzn. Możesz po prostu nadać idelement svg, więc: `<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

Możesz dołączyć do swoich plików SVG łącze do zewnętrznego pliku css za pomocą:

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

Musisz to umieścić po otwarciu tagu:

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

Nie jest to idealne rozwiązanie, ponieważ musisz zmodyfikować pliki svg, ale modyfikujesz je raz, a wszystkie zmiany stylów można zrobić w jednym pliku css dla wszystkich plików svg.

Jacek Mamot
źródło
1
Wow, to działa, ale tylko 1 głos za ... czy to rozwiązanie jest dobre we wszystkich sytuacjach? To takie proste, dlaczego nie jest to wybrana odpowiedź?
Bruno Vincent
Chodzi o centralizację definicji stylu. Powiedzmy, że masz 10 SVG, które chcesz stylizować. Teraz musisz skopiować odniesienie do CSS do wszystkich SVG, na które ma to wpłynąć. A jeśli nazwa pliku / lokalizacja twojego CSS ulegnie zmianie, musisz zaktualizować go w 10 SVG. Klasa CSS jest o wiele bardziej symboliczna niż odniesienie do fizycznego pliku CSS.
Frans
Zwróć uwagę, że svg załadowany przez tag <img> nie załaduje zawartości zewnętrznej (np. Arkuszy stylów).
Moose Morals
7

Istnieje możliwość nadania stylu SVG poprzez dynamiczne utworzenie elementu stylu w JavaScript i dołączenie go do elementu SVG. Hacky, ale działa.

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

Jeśli chcesz, możesz wygenerować JavaScript dynamicznie w PHP - fakt, że jest to możliwe w JavaScript, otwiera niezliczone możliwości.

Pete
źródło
hej, faktycznie lubię twoje rozwiązanie i działa, ale muszę je zaadaptować na mojej stronie, jeśli chcesz pomóc w kursie systemu operacyjnego, mam wewnątrz <defs> tag stylu, mogę je ręcznie usunąć i uruchomić ten kod, aby utworzył styl, czy jest sposób, żebym mógł usunąć definicje, a następnie odtworzyć element tak jak ty lub po prostu go zaktualizować, a także adres URL ma błąd URL nie jest zdefiniowany, czy możesz pomóc, dziękuję
Kamel Mili
6

Jednym ze sposobów, które możesz zastosować, jest użycie filtrów CSS do zmiany wyglądu grafiki SVG w przeglądarce.

Na przykład, jeśli masz grafikę SVG, która używa wypełnienia w kolorze czerwonym w kodzie SVG, możesz zmienić jej kolor na fioletowy z ustawieniem obracania barwy o 180 stopni:

#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);
}

Poeksperymentuj z innymi ustawieniami obracania barwy, aby znaleźć żądane kolory.

Żeby było jasne, powyższy CSS trafia do CSS, który jest stosowany do twojego dokumentu HTML. Stylizujesz tag img w kodzie HTML, a nie stylizujesz kod SVG.

Pamiętaj, że to nie zadziała w przypadku grafiki, która ma wypełnienie w kolorze czarnym, białym lub szarym. Musisz mieć tam rzeczywisty kolor, aby obrócić odcień tego koloru.

Simon White
źródło
4

Bardzo szybkie rozwiązanie, aby mieć dynamiczny styl z zewnętrznym arkuszem stylów css, w przypadku, gdy używasz <object>tagu do osadzenia pliku svg.

Ten przykład doda klasę do <svg>znacznika głównego po kliknięciu elementu nadrzędnego.

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

element nadrzędny po kliknięciu:

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

wtedy możesz zarządzać swoim 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
źródło
nie wydaje się działać, czy możesz dodać działający przykład?
Jeanluca Scaljeri
4

Powinno to być możliwe, najpierw wstawiając zewnętrzne obrazy svg. Poniższy kod pochodzi z zastąpienia wszystkich obrazów SVG wbudowanym SVG autorstwa Jess Frazelle.

$('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);
  });
});
Lew
źródło
3
ważne jest, aby pamiętać, że zadziała to tylko wtedy, gdy obraz jest hostowany w tej samej domenie co html lub masz specjalnie skonfigurowaną zasadę crossdomain na serwerze obrazu. $ .get użyje ajax i nie załaduje obrazu z serwera zewnętrznego, jeśli nie ma prawidłowego nagłówka zezwolenia na dostęp
user151496
to jest legendarne
Tino Costa 'El Nino'
2

W przypadku użycia w <image>tagu plik SVG musi znajdować się w jednym pliku ze względu na ochronę prywatności. Ten błąd bugzilli zawiera więcej szczegółów na temat tego, dlaczego tak się dzieje. Niestety nie możesz użyć innego tagu, takiego jak tag, <iframe>ponieważ nie będzie on działał jako łącze, więc będziesz musiał osadzić CSS w <style>tagu w samym pliku.

Innym sposobem na to byłoby umieszczenie danych SVG w głównym pliku HTML, tj

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

Możesz stylizować to za pomocą zewnętrznego pliku CSS za pomocą <link>tagu HTML .

Robert Longson
źródło
2
Nie mogę umieścić stylów w plikach. Zamierzam zmienić kolory tych obrazów na podstawie schematu kolorów wybranego przez użytkownika dla mojej witryny. Moja obecna implementacja polega na dodaniu arkusza stylów do strony głównej, który nadpisuje style domyślne. Chciałem umieścić zmiany kolorów w tym pliku, aby wpłynąć na osadzoną grafikę SVG. Ale to nie zadziała, ponieważ muszę utworzyć link do arkusza stylów z pliku SVG (chyba że istnieje sposób na dodanie tego łącza do wszystkich plików SVG również przy użyciu JavaScript). Z pewnością istnieje sposób na zezwolenie na zewnętrzne pliki SVG, zewnętrzne pliki CSS, linki i podpowiedzi.
Jordan H,
1
Nie można robić tego, co chcesz, ze względu na model zabezpieczeń przeglądarki. Nie możesz używać javascript do manipulowania SVG, gdy jest używany jako obraz. Pomyśl o SVG, gdy jest używany jako obraz jak animowany plik png lub gif, wszystko w jednym pliku i bez dostępu do skryptów.
Robert Longson,
1

„Zamierzam zmienić kolory tych obrazów na podstawie schematu kolorów wybranego przez użytkownika dla mojej witryny”. - Jordan 10 godzin temu

Proponuję użyć do tego PHP. Naprawdę nie ma lepszego sposobu na zrobienie tego bez czcionek ikon, a jeśli nie chcesz ich używać, możesz spróbować tego:

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

A później możesz użyć tego pliku, filename.php?color=#ffffffaby uzyskać plik SVG w żądanym kolorze.

SeinopSys
źródło
6
Zwróć uwagę, że ten kod nie sprawdza danych wejściowych użytkownika - wszystko może być dostarczone jako kolor, a Twój SVG może być renderowany na kilka bardzo interesujących sposobów ... Nie jestem pewien, czy to dotyczy Ciebie, ale powinieneś ZAWSZE sprawdzać poprawność danych wejściowych użytkownika. Coś takiego pomogłoby: if (!preg_match('/^[#][0-9a-f]{6}$/i', $_GET['color'])) die('Oops!');(umieść to gdzieś w początkowym bloku PHP).
johndodo,
1

Co mi pasuje: tag stylu z regułą @import

<defs>
    <style type="text/css">
        @import url("svg-common.css");
    </style>
</defs>
Fordi
źródło
1

Wiem, że to stary post, ale żeby rozwiązać ten problem ... po prostu używasz swoich zajęć w złym miejscu: D

Przede wszystkim możesz użyć

svg { fill: red; }

w twoim, main.cssżeby było czerwone. To ma wpływ. Prawdopodobnie możesz również użyć selektorów węzłów, aby uzyskać określone ścieżki.

Po drugie, zadeklarowałeś klasę jako img-Tag.

<img class='socIcon'....

Właściwie powinieneś zadeklarować to w swoim SVG. jeśli masz różne ścieżki, możesz oczywiście zdefiniować więcej.

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

teraz możesz zmienić kolor według własnego main.cssuznania

.myClassForMyPath {
    fill: yellow;
}
Dwza
źródło
Próbowałem tego, ale to nie działa, jak wiele innych odpowiedzi już mówi. Nie możesz zastosować stylizacji do klas wewnątrz SVG.
Frans
@Frans czy dołączasz plik svg jako plik, czy masz źródło svg, jak w powyższym przykładzie? Ponieważ mam na uwadze, że zależy to od tego, jak używasz svg. Włączenie przez img nie zadziała.
Dwza
Dokładnie, działa tylko wtedy, gdy umieścisz SVG w kodzie HTML. Ale to nie jest to, co robi twój przykład. Używa zewnętrznego (tzn. Nie inline) SVG. Wygląda na to, że nie ma sposobu na stylizowanie zewnętrznego SVG za pomocą CSS w kodzie HTML.
Frans
na pewno wypróbowałeś mój przykład poprawnie? mam na myśli, zawiera plik css z zewnętrznego? <?xml-stylesheet href="stylesheets/main.css" type="text/css"?>
Dwza
OK, teraz widzę, masz <?xml-stylesheet ... ?>deklarację w swoim SVG. Myślę, że to zadziała. Jest podobny do innych odpowiedzi, w których zaleca się umieszczenie <link rel="stylesheet" ... >wewnątrz SVG. Ma również te same problemy (musisz zaktualizować każdy plik SVG, aby wskazywał na arkusz stylów, a każda zmiana nazwy lub lokalizacji arkusza stylów oznacza konieczność ponownej zmiany wszystkich plików SVG).
Frans
1
  1. Do stylów zewnętrznych

<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. Do stylów wewnętrznych

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

Uwaga: Style zewnętrzne nie będą działać, jeśli umieścisz wewnątrz <img>znacznika SVG . Idealnie sprawdzi się wewnątrz <div>metki

Yuvraj Patil
źródło
0

@leo to wersja angularJS, jeszcze raz dziękuję

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

                } );

            } );
        }

    }

}

} );
Tino Costa „El Nino”
źródło
-1

Ta metoda zadziała, jeśli plik svg jest wyświetlany w przeglądarce internetowej, ale jak tylko ten kod zostanie przesłany na serwer, a klasa ikony SVG zostanie zakodowana tak, jakby była obrazem tła, kolor zostanie utracony i powróci do domyślnego koloru . Wygląda na to, że kolor nie może zostać zmieniony z zewnętrznego arkusza stylów, mimo że zarówno klasa svg dla koloru, jak i klasa najwyższej warstwy dla wyświetlania i pozycja svg są odwzorowane w tym samym katalogu.

HTMLGUY1999
źródło