Come modellare SVG con CSS esterni?


102

Ho diversi grafici SVG di cui vorrei modificare i colori tramite i miei fogli di stile esterni, non direttamente all'interno di ogni file SVG. Non metto la grafica in linea, ma la memorizzo nella cartella delle immagini e le indico.

Li ho implementati in questo modo per consentire il funzionamento dei suggerimenti e li ho anche inseriti in un <a>tag per consentire un collegamento.

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

Ed ecco il codice della grafica 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>

Ho inserito quanto segue nel mio file CSS esterno (main.css):

.socIcon g {fill:red;}

Tuttavia non ha alcun effetto sulla grafica. Ho anche provato .socIcon g path {} e .socIcon path {}.

Qualcosa non va, forse la mia implementazione non consente modifiche CSS esterne o ho perso un passaggio? Apprezzerei davvero il tuo aiuto! Ho solo bisogno della possibilità di modificare i colori della grafica SVG tramite il mio foglio di stile esterno, ma non posso perdere il tooltip e la capacità di collegamento. (Potrei essere in grado di vivere senza suggerimenti però.) Grazie!



Prova a svg { fill:red; }dare al tuo percorso un nome di classe. Ad esempio, <path class="socIcon" d="M28.44 ..... />questo dovrebbe fare il trucco.
Dwza

Risposte:


92

Il tuo file main.css avrebbe effetto sul contenuto dell'SVG solo se il file SVG è incluso in linea nell'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>

Se vuoi mantenere il tuo SVG nei file, il CSS deve essere definito all'interno del file SVG.

Puoi farlo con un tag di stile:

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>

È possibile utilizzare uno strumento sul lato server per aggiornare il tag di stile a seconda dello stile attivo. In ruby ​​potresti ottenere questo risultato con Nokogiri. SVG è solo XML. Quindi ci sono probabilmente molte librerie XML disponibili che possono probabilmente raggiungere questo obiettivo.

Se non sei in grado di farlo, dovrai semplicemente usarli come se fossero PNG; creando un set per ogni stile e salvando i loro stili in linea.


17
Ciò significa che non esiste alcun metodo per trarre vantaggio dalla memorizzazione nella cache di SVG e dall'applicazione di stili diversi? Inline non sembra memorizzare correttamente nella cache, mentre altri metodi richiederebbero la creazione di molte versioni dell'immagine, eliminando qualsiasi vantaggio derivante dalla memorizzazione nella cache.
msg45f

Un altro modo è codificare gli SVG come uris di dati dell'immagine di sfondo, con colori diversi su ciascuna versione e fare affidamento su gzip per ridurre le dimensioni del file a causa della duplicazione.
Ruskin

1
Nel mio caso volevo sovrascrivere gli stili degli elementi dall'SVG. Il mio CSS non funzionava, perché gli stili degli elementi avevano una priorità più alta. La soluzione più semplice è stata quella di aggiungere un! Importante allo stile CSS per SVG. Poi è andato tutto bene. Se vuoi evitare! Important, devi spostare gli stili degli elementi nel CSS.
David Gausmann

peccato che tu non possa caricare un foglio di stile all'interno di un svg da un URL
clayRay

1
@clayRay potrai farlo in questo modo una volta che SVG2 avrà completato la bozza w3.org/TR/SVG2/styling.html#LinkElement
RGB

51

Puoi fare quello che vuoi, con un (importante) avvertimento: i percorsi all'interno del tuo simbolo non possono essere stilizzati in modo indipendente tramite CSS esterno - puoi solo impostare le proprietà per l'intero simbolo con questo metodo. Quindi, se hai due percorsi nel tuo simbolo e vuoi che abbiano colori di riempimento diversi, questo non funzionerà, ma se vuoi che tutti i tuoi percorsi siano uguali, dovrebbe funzionare.

Nel tuo file html, vuoi qualcosa del genere:

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

E nel file SVG esterno vuoi qualcosa del genere:

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

Scambia la classe sul svgtag (nel tuo html) da fill-reda fill-bluee ta-da ... hai il blu invece del rosso.

È possibile aggirare parzialmente la limitazione di essere in grado di indirizzare i percorsi separatamente con CSS esterni mescolando e abbinando il CSS esterno con alcuni CSS in linea su percorsi specifici, poiché il CSS in linea avrà la precedenza. Questo approccio funzionerebbe se stai facendo qualcosa come un'icona bianca su uno sfondo colorato, in cui vuoi cambiare il colore dello sfondo tramite il CSS esterno ma l'icona stessa è sempre bianca (o viceversa). Quindi, con lo stesso HTML di prima e qualcosa di simile a questo codice svg, otterrai uno sfondo rosso e un percorso in primo piano bianco:

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

buona risposta .. penso che l'avvertenza dovrebbe essere davvero: supporto browser, però! buon riferimento (più dettagli rispetto a caniuse): css-tricks.com/svg-fragment-identifiers-work
ptim

Questa è una soluzione! In realtà non è necessario racchiudere l'intero contenuto svg in un symbolelemento, cioè puoi semplicemente dare un idelemento svg, quindi: `<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

Puoi includere nei tuoi file SVG un collegamento a un file CSS esterno utilizzando:

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

Devi metterlo dopo aver aperto il tag:

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

Non è una soluzione perfetta, perché devi modificare i file svg, ma li modifichi una volta e tutte le modifiche allo stile possono essere eseguite in un file css per tutti i file svg.


1
Wow, funziona, ma solo 1 voto positivo ... questa soluzione è valida per tutte le situazioni? E 'così semplice, perché non è questa la risposta scelta?
Bruno Vincent

Il punto è centralizzare le tue definizioni di stile. Supponiamo che tu abbia 10 SVG che desideri modellare. Ora devi copiare un riferimento al CSS in tutti gli SVG che devono essere interessati. E se il nome del file / posizione del tuo CSS cambia, devi aggiornarlo in 10 SVG. Una classe CSS sembra molto più simbolica di un riferimento a un file CSS fisico.
Frans

Nota che svg caricato tramite un tag <img> non caricherà contenuto esterno (ad esempio fogli di stile).
Moose Morals il

7

È possibile applicare uno stile a un SVG creando dinamicamente un elemento di stile in JavaScript e aggiungendolo all'elemento SVG. Hacky, ma funziona.

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

È possibile generare JavaScript dinamicamente in PHP se lo si desidera: il fatto che ciò sia possibile in JavaScript apre una miriade di possibilità.


hey in realtà mi piace la tua soluzione e funziona ma devo adottarla sulla mia posizione se sei disposto ad aiutare il corso del sistema operativo, ho dentro <defs> un tag di stile posso cancellarli manualmente ed eseguire questo codice in modo che crei uno stile, c'è un modo in cui posso eliminare le def, quindi ricreare l'elemento come hai fatto tu o semplicemente aggiornarlo, e anche l'URL ha ricevuto un errore l'URL non è definito puoi per favore aiutarmi, grazie
Kamel Mili

6

Un approccio che puoi adottare è semplicemente usare i filtri CSS per modificare l'aspetto della grafica SVG nel browser.

Ad esempio, se hai un'immagine SVG che utilizza un colore di riempimento rosso all'interno del codice SVG, puoi trasformarla in viola con un'impostazione di rotazione della tonalità di 180 gradi:

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

Sperimenta con altre impostazioni di rotazione della tonalità per trovare i colori che desideri.

Per essere chiari, il CSS sopra va nel CSS applicato al tuo documento HTML. Stai definendo lo stile del tag img nel codice HTML, non lo stile del codice dell'SVG.

E nota che questo non funzionerà con la grafica che ha un riempimento di nero, bianco o grigio. Devi avere un colore reale lì dentro per ruotare la tonalità di quel colore.


4

Una soluzione molto rapida per avere uno stile dinamico con un foglio di stile CSS esterno, nel caso in cui utilizzi il <object>tag per incorporare il tuo svg.

Questo esempio aggiungerà una classe al <svg>tag radice facendo clic su un elemento genitore.

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

al clic sull'elemento genitore:

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

quindi puoi gestire il tuo 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;
}

non sembra funzionare, potresti aggiungere un esempio funzionante?
Jeanluca Scaljeri

4

Dovrebbe essere possibile farlo inserendo prima le immagini svg esterne. Il codice seguente proviene dalla sostituzione di tutte le immagini SVG con SVG in linea di 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);
  });
});

3
È importante notare che questo funzionerà solo se l'immagine è ospitata sullo stesso dominio dell'html o se si dispone di una policy di crossdomain appositamente configurata sul server di immagini. $ .get utilizzerà ajax e non caricherà l'immagine dal server esterno se non c'è un'intestazione di autorizzazione all'accesso valida
user151496

questo è leggendario
Tino Costa 'El Nino'

2

Quando viene utilizzato in un <image>tag SVG deve essere contenuto in un unico file per motivi di privacy. Questo bug di bugzilla ha più dettagli sul motivo esatto per cui è così. Sfortunatamente non puoi usare un tag diverso come un <iframe>perché non funzionerà come collegamento, quindi dovrai incorporare il CSS in un file<style> tag all'interno del file stesso.

Un altro modo per farlo sarebbe avere i dati SVG all'interno del file html principale, ad es

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

Puoi modellarlo con un file CSS esterno utilizzando il <link>tag HTML .


2
Non riesco a mettere gli stili all'interno dei file. In realtà cambierò i colori di queste immagini in base alla combinazione di colori scelta dall'utente per il mio sito. La mia attuale implementazione consiste nell'aggiungere un foglio di stile alla pagina principale che sovrascrive gli stili predefiniti. Volevo inserire i cambiamenti di colore in quel file per influenzare la grafica SVG incorporata. Ma non funzionerebbe perché devo collegarmi al foglio di stile dall'interno del file SVG (a meno che non ci sia un modo per aggiungere quel collegamento a tutti i file SVG usando JavaScript). Sicuramente c'è un modo per consentire file SVG esterni, CSS esterni, collegamenti e suggerimenti.
Jordan H

1
Non è possibile fare ciò che vuoi a causa del modello di sicurezza del browser. Non è possibile utilizzare JavaScript per manipolare SVG quando viene utilizzato come immagine. Pensa a SVG quando viene utilizzato come immagine come un file png o gif animato, tutto in un file e senza accesso allo script.
Robert Longson

1

"In realtà cambierò i colori di queste immagini in base alla combinazione di colori scelta dall'utente per il mio sito". - Jordan 10 ore fa

Ti suggerisco di usare PHP per questo. Non c'è davvero modo migliore per farlo senza i caratteri delle icone, e se resisti a usarli, potresti provare questo:

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

E in seguito potresti usare questo file filename.php?color=#ffffffper ottenere il file svg nel colore desiderato.


6
Nota che questo codice non controlla l'input dell'utente: qualsiasi cosa potrebbe essere fornita come colore e il tuo SVG potrebbe essere reso in alcuni modi molto interessanti ... Non sono sicuro che ti influisca, ma dovresti prendere l'abitudine di convalidare SEMPRE l'input dell'utente. Qualcosa del genere aiuterebbe: if (!preg_match('/^[#][0-9a-f]{6}$/i', $_GET['color'])) die('Oops!');(mettilo da qualche parte nel blocco PHP iniziale).
johndodo

1

Cosa funziona per me: tag di stile con regola @import

<defs>
    <style type="text/css">
        @import url("svg-common.css");
    </style>
</defs>

1

So che è un vecchio post, ma solo per chiarire questo problema ... stai semplicemente usando le tue classi nel posto sbagliato: D

Prima di tutto potresti usare

svg { fill: red; }

nel tuo main.cssper ottenerlo rosso. Questo ha effetto. È possibile utilizzare anche i selettori di nodo per ottenere percorsi specifici.

La seconda cosa è che hai declamato la classe al imgtag.

<img class='socIcon'....

In realtà dovresti dichiararlo all'interno del tuo SVG. se hai percorsi diversi potresti definirne di più ovviamente.

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

ora potresti cambiare il colore nel tuo main.csslike

.myClassForMyPath {
    fill: yellow;
}

Provato, non funziona, come dicono già molte altre risposte. Non puoi applicare lo stile alle classi all'interno di SVG.
Frans

@Frans stai includendo uno svg come file o hai la tua fonte svg come nell'esempio sopra? Perché ho in mente che questo dipende da come usi svg. Compreso da img non funzionerà.
Dwza

Esatto, funziona solo se inline l'SVG nel tuo HTML. Ma non è quello che fa il tuo esempio. Utilizza un SVG esterno (cioè non in linea). Non sembra esserci alcun modo per modellare un SVG esterno con CSS nel tuo HTML.
Frans

sicuro di aver provato il mio esempio corretto? voglio dire, incluso un file css da esterno? <?xml-stylesheet href="stylesheets/main.css" type="text/css"?>
Dwza

OK, ora capisco, hai una <?xml-stylesheet ... ?>dichiarazione all'interno del tuo SVG. Immagino che funzionerebbe. È simile ad altre risposte che raccomandano un <link rel="stylesheet" ... >interno all'SVG. Ha anche gli stessi problemi (è necessario aggiornare ogni singolo SVG in modo che punti al foglio di stile, e qualsiasi cambiamento nel nome o nella posizione del foglio di stile significa dover cambiare di nuovo tutti gli SVG).
Frans

1
  1. Per stili esterni

<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. Per stili interni

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

Nota: gli stili esterni non funzioneranno se includi SVG all'interno del <img>tag. Funzionerà perfettamente all'interno del <div>tag


0

@leo ecco la versione angularJS, grazie ancora

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

Questo metodo funzionerà se lo svg viene visualizzato all'interno di un browser web ma non appena questo codice viene caricato sul server e la classe per l'icona svg viene codificata come se fosse un'immagine di sfondo il colore viene perso e torna al colore predefinito . Sembra che il colore non possa essere modificato dal foglio di stile esterno anche se sia la classe svg per il colore che la classe di livello superiore per la visualizzazione e la posizione dello svg sono entrambe mappate nella stessa directory.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.