How to style SVG with external CSS?
Solution 1
Your main.css file would only have an effect on the content of the SVG if the SVG file is included inline in the 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>
If you want to keep your SVG in files, the CSS needs to be defined inside of the SVG file.
You can do it with a style tag:
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>
You could use a tool on the server side to update the style tag depending on the active style. In ruby you could achieve this with Nokogiri. SVG is just XML. So there are probably many XML libraries available that can probably achieve this.
If you're not able to do that, you will have to just have to use them as though they were PNGs; creating a set for each style, and saving their styles inline.
Solution 2
You can do what you want, with one (important) caveat: the paths within your symbol can't be styled independently via external CSS -- you can only set the properties for the entire symbol with this method. So, if you have two paths in your symbol and want them to have different fill colors, this won't work, but if you want all your paths to be the same, this should work.
In your html file, you want something like this:
<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>
And in the external SVG file you want something like this:
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="example" viewBox="0 0 256 256">
<path d="M120...." />
</symbol>
</svg>
Swap the class on the svg
tag (in your html) from fill-red
to fill-blue
and ta-da... you have blue instead of red.
You can partially get around the limitation of being able to target the paths separately with external CSS by mixing and matching the external CSS with some in-line CSS on specific paths, since the in-line CSS will take precedence. This approach would work if you're doing something like a white icon against a colored background, where you want to change the color of the background via the external CSS but the icon itself is always white (or vice-versa). So, with the same HTML as before and something like this svg code, you'll get you a red background and a white foreground path:
<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>
Solution 3
You can include in your SVG files link to external css file using:
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="mystyles.css" type="text/css"/>
You need to put this after opening tag:
<svg>
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="mystyles.css" type="text/css"/>
<g>
<path d=.../>
</g>
</svg>
It's not perfect solution, because you have to modify svg files, but you modify them once and than all styling changes can be done in one css file for all svg files.
Solution 4
It is possible to style an SVG by dynamically creating a style element in JavaScript and appending it to the SVG element. Hacky, but it works.
<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>
You could generate the JavaScript dynamically in PHP if you want to - the fact that this is possible in JavaScript opens a myriad of possibilities.
Solution 5
One approach you can take is just to use CSS filters to change the appearance of the SVG graphics in the browser.
For example, if you have an SVG graphic that uses a fill color of red within the SVG code, you can turn it purple with a hue-rotate setting of 180 degrees:
#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);
}
Experiment with other hue-rotate settings to find the colors you want.
To be clear, the above CSS goes in the CSS that is applied to your HTML document. You are styling the img tag in the HTML code, not styling the code of the SVG.
And note that this won’t work with graphics that have a fill of black or white or gray. You have to have an actual color in there to rotate the hue of that color.
Comments
-
Jordan H almost 2 years
I have several SVG graphics I'd like to modify the colors of via my external style sheets - not directly within each SVG file. I'm not putting the graphics in-line, but storing them in my images folder and pointing to them.
I have implemented them in this way to allow tooltips to work, and I also wrapped each in an
<a>
tag to allow a link.<a href='http://youtube.com/...' target='_blank'><img class='socIcon' src='images/socYouTube.svg' title='View my videos on YouTube' alt='YouTube' /></a>
And here is the code of the SVG graphic:
<?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>
I put the following in my external CSS file (main.css):
.socIcon g {fill:red;}
Yet it has no effect on the graphic. I also tried .socIcon g path {} and .socIcon path {}.
Something isn't right, perhaps my implementation doesn't allow external CSS modifications, or I missed a step? I'd really appreciate your help! I just need the ability to modify the colors of the SVG graphic via my external stylesheet, but I cannot lose the tooltip and link ability. (I may be able to live without tooltips though.) Thanks!
-
Jordan H over 10 yearsI cannot put the styles within the files. I am actually going to change the colors of these images based on what color scheme the user has chosen for my site. My current implementation is to add a stylesheet to the main page which overwrites the default styles. I wanted to put the color changes in that file to affect the embedded SVG graphics. But that wouldn't work cuz I have to link to the stylesheet from within the SVG file (unless there's a way to add that link to all SVG files using JavaScript as well). Surely there's a way to allow external SVG files, external CSS, links, and tooltips.
-
Robert Longson over 10 yearsIt is not possible to do what you want to do because of the browser's security model. You cannot use javascript to manipulate SVG when used as an image. Think of SVG when used as an image as like an animated png or gif file, all in one file and no scripting access.
-
johndodo over 10 yearsNote that this code does not check user input - anything could be supplied as color and your SVG might be rendered in some very interesting ways... Not sure if it affects you, but you should make it a habit to ALWAYS validate user input. Something like this would help:
if (!preg_match('/^[#][0-9a-f]{6}$/i', $_GET['color'])) die('Oops!');
(put it somewhere in the start PHP block). -
msg45f over 9 yearsDoes this mean that there is no method to benefit from caching the SVG and applying varied styling? Inline doesn't seem to cache well, while other methods would require creating many version of the image, eliminating any benefit from caching them.
-
ptim almost 9 yearsgood answer.. i think the caveat should really be: Browser Support, though! good reference (more detail than caniuse): css-tricks.com/svg-fragment-identifiers-work
-
user151496 over 8 yearsit's importat to note that this will work only if you have the image hosted on the same domain as the html, or have a specially configured crossdomain policy on the image server. $.get will use ajax and fail to load the image from external server if there's no valid allow-access header
-
Ruskin about 7 yearsAnother way is to encode the SVGs as background-image data uris, with different colours on each version and rely on gzip to reduce file size due to the duplication.
-
Kamel Mili almost 7 yearshey i actually like you solution and it's working but i need to adopt it on my situtation if you're willing to help os course , i have inside <defs> a style tag i can delete them manually and run this code so it would create a style , is there's a way i can delete the defs then recreate the element like you did or just update it , and also the url got an error url is not defined can you please help , thank you
-
Jeanluca Scaljeri over 6 yearsdoesn't seem to work, could you add a working example?
-
Tino Costa 'El Nino' over 5 yearsthis is legendary
-
SimoneMSR about 5 yearsThis is a solution! Actually there is no need to wrap the whole svg content in a
symbol
element, i.e. you can just give anid
to the svg element, so: ` <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> ` -
David Gausmann over 4 yearsIn my case I wanted to override element styles from the SVG. My CSS didn't work, because the element styles had a higher priority. The most simple solution was it to add an !important to the CSS style for the SVG. Then everything was fine. If you want to avoid !important, you need to move the element styles into the CSS.
-
Bruno Vincent about 4 yearsWow, this is works, yet only 1 upvote...is this solution good for all situations? It' so simple, why isn't this the chosen answer?
-
clayRay almost 4 yearsshame you can't load a stylesheet inside an svg from a URL
-
raddrick almost 4 years@clayRay you will be able to do it that way once SVG2 is complete draft w3.org/TR/SVG2/styling.html#LinkElement
-
Frans almost 4 yearsTried this, it doesn't work, like many of the other answers already say. You can't apply styling to classes inside the SVG.
-
Frans almost 4 yearsThe whole point is centralizing your style definitions. Let's say you have 10 SVGs you want to style. Now you need to copy in a reference to the CSS into all the SVGs that need to be affected. And if the file name / location of your CSS changes, you need to update it in 10 SVGs. A CSS class feels a lot more symbolic than a reference to a physical CSS file.
-
Dwza almost 4 years@Frans are you including a svg as a file or do you have your svg source like in the example above? Because I have in mind that this depends on how you use svg. Including by img wont work.
-
Moose Morals almost 4 yearsNote that svg loaded through an <img> tag will not load external content (e.g., stylesheets).
-
Frans almost 4 yearsExactly, it only works if you inline the SVG in your HTML. But that is not what your example does. It uses an external (i.e. not inline) SVG. There seems to be no way to style an external SVG with CSS in your HTML.
-
Dwza almost 4 yearssure you tried my example correct? i mean, included a css file from external ?
<?xml-stylesheet href="stylesheets/main.css" type="text/css"?>
-
Frans almost 4 yearsOK, now I see, you have an
<?xml-stylesheet ... ?>
declaration inside your SVG. I guess that would work. It's similar to other answers recommending a<link rel="stylesheet" ... >
inside the SVG. It also has the same problems (you need to update every single SVG to point to the stylesheet, and any change in name or location of the stylesheet means having to change all the SVGs again). -
Niklas over 3 yearsHaving a style tag as a content of the defs element is permitted. That's at least what the usage notes on Mozilla states. developer.mozilla.org/en-US/docs/Web/SVG/Element/defs
-
Armen Michaeli over 3 years@Frans everything you remarked applies the same way to HTML, so this isn't SVG-specific. In fact it's a very general linking problem -- there are indeed both benefits and drawbacks to mark up links between documents.
-
BBaysinger almost 3 yearsI came here hoping to find something like this. Woo, hotness!
-
BarryCap almost 3 yearsAs said by Moose Morals, with this method, we cannot use an
<img>
tag and load external CSS inside SVG; I would therefore recommend the use of<object>
, with thedata
attribute instead of thesrc
. -
BarryCap about 2 years
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="main.css" type="text/css"/>
also works