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).
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.
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>
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.
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.
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.
It should be possible to do by first inlining the external svg images. The code below comes from replace all SVG images with inline SVG by 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);
});
});
A very quick solution to have dynamic style with an external css stylesheet, in case you are using the <object> tag to embed your svg.
This example will add a class to the root <svg> tag on click on a parent element.
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");
}
});
on click parent element :
<svg xmlns="http://www.w3.org/2000/svg" viewBox="" class="selected">
then you can manage your 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;
}
For External styles
<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>
For Internal Styles
<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>
Note: External Styles will not work if you include SVG inside <img> tag. It will work perfectly inside <div> tag
When used in an <image> tag SVG must be contained in a single file for privacy reasons. This bugzilla bug has more details on exactly why this is so. Unfortunately you can't use a different tag such as an <iframe> because that won't work as a link so you'll have to embed the CSS in a <style> tag within the file itself.
One other way to do this would be to have the SVG data within the main html file i.e.
<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>
You could style that with an external CSS file using the HTML <link> tag.
What works for me: style tag with #import rule
<defs>
<style type="text/css">
#import url("svg-common.css");
</style>
</defs>
#leo here is the angularJS version, thanks again
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 );
} );
} );
}
}
}
} );
In my case, I have applied display:block in outer class.
Need to experiment, where it fits.
Inside inline svg adding class and style does not even remove the above white-space.
See: where the display:block gets applied.
<div class="col-3 col-sm-3 col-md-2 front-tpcard"><a class="noDecoration" href="#">
<img class="img-thumbnail img-fluid"><svg id="Layer_1"></svg>
<p class="cardtxt">Text</p>
</a>
</div>
The class applied
.front-tpcard .img-thumbnail{
display: block; /*To hide the blank whitespace in svg*/
}
This worked for me.
Inner svg class did not worked
I know its an old post, but just to clear this problem... you're just using your classes at the wrong place :D
First of all you could use
svg { fill: red; }
in your main.css to get it red. This does have effect. You could probably use node selectors as well to get specific paths.
Second thing is, you declared the class to the img-tag.
<img class='socIcon'....
You actually should declare it inside your SVG. if you have different paths you could define more of course.
<?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>
Now you could change the color in your main.css like
.myClassForMyPath {
fill: yellow;
}
As described in answers here and in other related questions, stylesheets only apply to the current DOM. As such, you need to make the svg part of the document's DOM, by inlining it inside the html, or including it inside the DOM using javascript.
That's what I ended up doing there:
<object type="image/svg+xml" data="illustration.svg"
onload="this.parentNode.replaceChild(this.contentDocument.documentElement, this);">
</object>
While that solution works really well for me, only use it on documents you control, as inline loading an svg from an untrusted source gives that source the ability to include at least arbitrary scripts, css and other elements inside your HTML, breaking the sandbox.
I haven't investigated how well caching works with this, but it should work as well as with img tags, given that the javascript function is ran after the element loads. Feel free to edit this.
If javascript is disabled, the svg is not included into the DOM, and the style is not applied, so make sure the default style is usable. CSS custom properties (variables) with fallbacks work quite well for that use-case.
Not fully tested yet, but Ive found a nice way to treat external svg files like inlines. No Javascript, no server-code - just a document root-id:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="svgroot">...
After this we're allowed to use it with an SVG2-Tag which seems to be supported by Chrome/Edge - Blink; Firefox - Gecko; Safari - Webkit:
<html>
<head>
<style>
.primary-text {
color: green;
}
.icon {
height: 100px;
width: 100px;
fill: currentColor;
}
</style>
</head>
<body>
<h3>svg Fill currentColor</h3>
<svg class="primary-text icon">
<use href="example.svg#svgroot"></use>
</svg>
</body>
</html>
Going further, you're able to create a resource-dictionary/sprite file:
<svg xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 512 512" id="apple">...
<svg viewBox="0 0 512 512" id="peach">...
</svg>
Honestly, this seems too good to be true... :D
// Edit:
This seems to be a well respected approach:
https://icons.getbootstrap.com/#usage
"I am actually going to change the colors of these images based on what color scheme the user has chosen for my site." - Jordan 10 hours ago
I suggest you to use PHP for this. There's really no better way to do this without icon fonts, and if you resist using them, you could try this:
<?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>
And later you could use this file as filename.php?color=#ffffff to get the svg file in the desired color.
This method will work if the svg is viewed within a web browser but as soon as this code is uploaded to the sever and the class for the svg icon is coded as if it was a background image the color is lost and back to the default color. Seems like the color can not be changed from the external style sheet even though both the svg class for the color and the top layer class for the display and position of the svg are both mapped to the same directory.
Related
AndroidSVG allows for dynamic color change as explained here.
The following code works for 95% of my icon library ...
SVGImageView svgIV;
......
String color = "#FEFBDE"
svgIV.setCSS(String.format("* { fill:%s; }", color););
... but fails on Inkscape SVGs such as this:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="64"
height="64"
id="svg2"
style="display:inline">
<defs
id="defs4" />
<g
transform="translate(403.45398,-1106.6063)"
id="layer1"
style="display:inline">
<g
transform="matrix(7.6594323,0,0,7.6594323,2702.0005,-7795.5738)"
id="g3766">
<path
d="m -401.264,1167.506 0,2.8346 1.41732,0"
id="path4668"
style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
d="m -401.264,1162.5164 c 0,0 -0.5132,-0.012 -0.5132,0.6511 0,0.3318 0,0.1926 0,0.5423 0,0.3989 -0.64122,0.3626 -0.64122,1.0261 0,0.5996 0.047,0.4425 0,0.8135 -0.047,0.371 -0.76981,0.356 -0.76981,1.1045 0,0.9955 0.64122,0.8521 0.64122,0.8521 l 1.28301,0"
id="path4711-1"
style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
<path
d="m -401.264,1162.5164 c 0,0 0.5132,-0.012 0.5132,0.6511 0,0.3318 0,0.1926 0,0.5423 0,0.3989 0.64122,0.3626 0.64122,1.0261 0,0.5996 -0.047,0.4425 0,0.8135 0.047,0.371 0.76981,0.356 0.76981,1.1045 0,0.9955 -0.64122,0.8521 -0.64122,0.8521 l -1.28301,0"
id="path4711-1-3"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.53149605;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
</g>
</g>
</svg>
What, if any, is the necessary CSS?
On reflection, this may be a more general CSS question:
How to override part of a style?
Normally (in CSS) the way you would achieve this would be via use of the !important flag.
svgIV.setCSS(String.format("* { fill:%s !important; }", color););
Unfortunately, the CSS system in AndroidSVG does not yet support !important. It's on my TODO list.
In the meantime, you will need to convert those SVGs to use either attributes (fill="whatever") or CSS. You can easily convert those files to use attribute form, by loading them into Inkscape and save as "Optimized SVG".
This fork was created in response to the question.
It allows full color control over any .svg via a user-defined callback and is great for users who do not wish to manually convert 2,735 Inkscape definitions to conform with the current restriction.
I grabbed an SVG file, a map of NY State, and would like to add classes to various elements (the counties).
I tried adding a class via javascript. The class was added but visually nothing happened. I tried inserting the class directly. That didn't work. I tried adding a fill to an existing ID but that didn't do anything.
The existing code looks something like:
<polygon id="St_Lawrence" class="highlight" points="404.480957,7.098633
As said I tried adding a class, adding fill information to the existing ID (St_Lawrence) but that didn't work. However adding a style inline worked (see below)
<polygon id="St_Lawrence" style="fill:#FF0000;" points="404.480957,7.098633
That, unfortunately, doesn't really help.
The basic code is below:
<svg xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
width="633.475098" height="475.573242" viewBox="0 0 633.475098 475.573242"
style="overflow:visible;enable-background:new 0 0 633.475098 475.573242" xml:space="preserve">
<g id="Layer_1">
<g fill="#FFFFFF" stroke="#000000" stroke-width="0.25">
<polygon id="St_Lawrence" points="404.480957,7.098633 404.581543,7.098633 404.581543,7.098633
406.171387,7.099609 406.171387,7.099609 406.218262,7.109375 406.218262,7.109375 406.313965,7.109375 408.001465,7.123047
408.001465,7.123047 408.050293,7.123047 408.050293,7.123047 410.122559,7.138672 410.591309,11.53125 410.591309,11.53125
EDIT:
I worked with another SVG file and got classes to work as they should. Don't know SVG well enough to decipher why this one works while the first one doesn't.
You can use CSS styles (whether based on class, id, or some other CSS selector) in SVG. It's a little tricky to mix inline attributes (such as individual fill="blue"), the style attribute (e.g. style="fill: blue;"), and stylesheets, because SVG doesn't interpret them in the order of precedence you might expect (or at least, I expect).
In the above map, id-based selectors are probably going to be more convenient, because the counties are named by id.
Here's an example of CSS styling by id:
<svg xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
width="633.475098" height="475.573242" viewBox="0 0 633.475098 475.573242"
style="overflow:visible;enable-background:new 0 0 633.475098 475.573242" xml:space="preserve">
<style type="text/css">
<![CDATA[
.st0{fill:#FFFFFF;stroke:#000000;stroke-width:0.25;}
.st1{fill:none;stroke:#000044;stroke-width:0.5;}
#St_Lawrence {
fill: blue; fill-opacity: 0.3;
}
#Queens {
fill: orange; fill-opacity: 0.9;
}
]]>
</style>
(with the rest of the document the same)
This highlights the two counties with fill colors:
Works fine with the following:
<style type="text/css">
<![CDATA[
.st0{fill:#FFFFFF;stroke:#000000;stroke-width:0.25;}
.st1{fill:none;stroke:#000044;stroke-width:0.5;}
.highlight{fill:#00ff00;stroke:#000044;stroke-width:0.5;}
]]>
</style>
<g fill="#FFFFFF" stroke="#000000" stroke-width="0.25">
<polygon id="St_Lawrence" class="highlight" points="404.480957,7.098633
However, <polygon> already has a class="st0" which has a fill:#FFFFFF, so you probably want to change or remove the st0 class.
As a test you could just add .st0:hover{fill:red;} which will highlight the county when the mouse is moved over it:
<style type="text/css">
<![CDATA[
.st0{fill:#FFFFFF;stroke:#000000;stroke-width:0.25;}
.st0:hover{fill:red;}
.st1{fill:none;stroke:#000044;stroke-width:0.5;}
]]>
</style>
You need to apply the style to the icon enclosed in the <path> tag: style="stroke:var(--button-bg-color)"
<svg width="32" height="62" viewBox="0 0 32 62" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M25 37L31 31C31 31 27.3431 27.3431 25 25" style="stroke:var(--button-bg-color)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M31 61C14.4315 61 1 47.5685 1 31C1 14.4315 14.4315 1 31 1" stroke="#C4C4C4"/>
</svg>
I have single svg icon. which I have inserted in the document like this,
<img src="../assets/layouts/layout3/svgs/star-def.svg"
width="15" height="15" />
its displaying properly no issues, but what I want is , its need to change the color , in short , I need multiple color variants of the same icon using css. Means , I can change the class & the icon should become of that color.
I tried using, fill , but its not happening. my html & css below with adding fills.
html:-
<img src="../assets/layouts/layout3/svgs/star-def.svg" class="greenfill"
width="15" height="15" />
& css
.greenfill { fill:#569e26;}
Note
I had open the file in editor & changed the fill color from there & have a different coloured icon , but I dont want this.
Thanks in advance.
Please check the answer here
http://jsfiddle.net/wuSF7/462/
svg {
width: 350px; height: 350px;
}
svg path {
fill: yellow !important;
}
I think you should create a reference with g or symbol in SVG and then use it the times you need with a class for each color.
It depends on the item you are working on with to color its fill or stroke and the same if you have to select a path a circle or whatever. You can select the whole object .greenfill{fill:#569e26;} or each subelement .greenfill g rect{fill:#569e26;}.
<svg>
<style>
.greenfill{fill:#569e26;}
.redfill{fill:red;}
</style>
<defs>
<g id="star-def"><!-- ... --></g>
</defs>
<use xlink:href="#star-def" class="greenfill" />
<use xlink:href="#star-def" class="redfill" />
<!-- ... -->
</svg>
I've been trying to find a solution for handling SVG elements used as background images via CSS:
.icon.arrow-down
{
background-image: url( 'images/spritesheet.svg#arrow-down' );
}
I'm using :target directly in the SVG file in order to target a particular layer (or "group") within the combined SVG spritesheet.
<?xml version="1.0" encoding="utf-8" ?>
<svg class="icon" id="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="50px" height="50px" viewBox="0 0 50 50">
<defs>
<style>
rect, line { shape-rendering: crispEdges; }
svg .icon { display: none; }
svg .icon:target { display: inline; }
</style>
</defs>
<!-- Arrows -->
<g class="icon" id="arrow-down" transform="translate(0,12.5)">
<path fill="#F00" d="M 0,0 50,0 25,25 z" />
</g>
<g class="icon" id="arrow-up" transform="translate(0,12.5)">
<path fill="#F00" d="M 0,25 50,25 25,0 z" />
</g>
...
</svg>
This works fine for Firefox and IE9+, but in Chrome it seems to be ignoring the #profile part. However, going to the SVG sheet directly in the browser, with the target id, yields the correct image.
Is this a bug in the way Chrome is handling :target in background images?
I'm trying to avoid having to separate everything into their own files, so only one resource is downloaded, but I don't know that it is possible yet.
Notice how the icons are not shown in Chrome, but are in other browsers: http://jsfiddle.net/sYL5F/1/
It's a known issue and is specific to using it as a background and apparently won't be fixed because of security concerns (Opera also doesn't display it). If you view the SVG directly, it works as you would expect.
https://code.google.com/p/chromium/issues/detail?id=128055#c6
SVG stacks will not be supported for CSS properties taking CSS Image
values. This includes, but is not limited to, background-image,
mask-image, border-image.
This is a resolution of the SVG and CSS WG to differ between resources
(like SVG gradients, masks, clipPath) and image values during parse
time of CSS. This is a security requirement to protect the users
privacy and safety.
See following discussions for further information:
http://lists.w3.org/Archives/Public/www-style/2012Oct/0406.html
http://lists.w3.org/Archives/Public/www-style/2012Oct/0765.html
You're just going to handle your SVG the same way you would an old fashioned sprite map.
For my latest project, I've implemented my own way of creating custom SVG parameters using a PHP MVC framework I've been working on. Essentially, I created a controller for linking to icons:
/icon/NAME_OF_ICON.svg?color=F00
My icon controller takes the filename and injects the GET parameters into the SVG file.
//define( ROOT, "path/to/webroot" );
//$filename = ...get filename from URL...;
$svg = simplexml_load_file( ROOT . "/assets/icons/{$filename}" );
if( isset( $_GET['color'] ) )
{
$svg->path->addAttribute( 'fill', '#' . $_GET['color'] );
}
header( "Content-type: image/svg+xml" );
echo $svg->asXML( );
I'll be adding code to cache the queried custom SVG's, eventually.
Is it possible to use an inline SVG definition in CSS?
I mean something like:
.my-class {
background-image: <svg>...</svg>;
}
Yes, it is possible. Try this:
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>");
}
http://jsfiddle.net/6WAtQ/
(Note that the SVG content needs to be url-escaped for this to work, e.g. # gets replaced with %23.)
This works in IE 9 (which supports SVG). Data-URLs work in older versions of IE too (with limitations), but they don’t natively support SVG.
If any of you have been going crazy trying to use inline SVG as a background, the escaping suggestions above do not quite work. For one, it does not work in IE, and depending on the content of your SVG the technique will cause trouble in other browsers, like FF.
If you base64 encode the svg (not the entire url, just the svg tag and its contents! ) it works in all browsers. Here is the same jsfiddle example in base64: http://jsfiddle.net/vPA9z/3/
The CSS now looks like this:
body { background-image:
url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PGxpbmVhckdyYWRpZW50IGlkPSdncmFkaWVudCc+PHN0b3Agb2Zmc2V0PScxMCUnIHN0b3AtY29sb3I9JyNGMDAnLz48c3RvcCBvZmZzZXQ9JzkwJScgc3RvcC1jb2xvcj0nI2ZjYycvPiA8L2xpbmVhckdyYWRpZW50PjxyZWN0IGZpbGw9J3VybCgjZ3JhZGllbnQpJyB4PScwJyB5PScwJyB3aWR0aD0nMTAwJScgaGVpZ2h0PScxMDAlJy8+PC9zdmc+");
Remember to remove any URL escaping before converting to base64. In other words, the above example showed color='#fcc' converted to color='%23fcc', you should go back to #.
The reason why base64 works better is that it eliminates all the issues with single and double quotes and url escaping
If you are using JS, you can use window.btoa() to produce your base64 svg; and if it doesn't work (it might complain about invalid characters in the string), you can simply use https://www.base64encode.org/.
Example to set a div background:
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>
With JS you can generate SVGs on the fly, even changing its parameters.
One of the better articles on using SVG is here : http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/
My solution was https://yoksel.github.io/url-encoder/
You just simply insert your svg and getting back background-image code
For people who are still struggling, I managed to get this working on all modern browsers IE11 and up.
base64 was no option for me because I wanted to use SASS to generate SVG icons based on any given color. For example: #include svg_icon(heart, #FF0000); This way I can create a certain icon in any color, and only have to embed the SVG shape once in the CSS. (with base64 you'd have to embed the SVG in every single color you want to use)
There are three things you need be aware of:
URL ENCODE YOUR SVG
As others have suggested, you need to URL encode your entire SVG string for it to work in IE11. In my case, I left out the color values in fields such as fill="#00FF00" and stroke="#FF0000" and replaced them with a SASS variable fill="#{$color-rgb}" so these can be replaced with the color I want. You can use any online converter to URL encode the rest of the string. You'll end up with an SVG string like this:
%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
OMIT THE UTF8 CHARSET IN THE DATA URL When creating your data URL, you need to leave out the charset for it to work in IE11.
NOT background-image: url( data:image/svg+xml;utf-8,%3Csvg%2....)
BUT background-image: url( data:image/svg+xml,%3Csvg%2....)
USE RGB() INSTEAD OF HEX colors Firefox does not like # in the SVG code. So you need to replace your color hex values with RGB ones.
NOT fill="#FF0000"
BUT fill="rgb(255,0,0)"
In my case I use SASS to convert a given hex to a valid rgb value. As pointed out in the comments, it's best to URL encode your RGB string as well (so comma becomes %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');
}
}
I realize this might not be the best solution for very complex SVG's (inline SVG never is in that case), but for flat icons with only a couple of colors this really works great.
I was able to leave out an entire sprite bitmap and replace it with inline SVG in my CSS, which turned out to only be around 25kb after compression. So it's a great way to limit the amount of requests your site has to do, without bloating your CSS file.
On Mac/Linux, you can easily convert a SVG file to a base64 encoded value for CSS background attribute with this simple bash command:
echo "background: transparent url('data:image/svg+xml;base64,"$(openssl base64 < path/to/file.svg)"') no-repeat center center;"
Tested on Mac OS X.
This way you also avoid the URL escaping mess.
Remember that base64 encoding an SVG file increase its size, see css-tricks.com blog post.
I've forked a CodePen demo that had the same problem with embedding inline SVG into CSS. A solution that works with SCSS is to build a simple url-encoding function.
A string replacement function can be created from the built-in str-slice, str-index functions (see css-tricks, thanks to Hugo Giraudel).
Then, just replace %,<,>,",', with the %xxcodes:
#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;
}
There is also a image-inline helper function available in Compass, but since it is not supported in CodePen, this solution might probably be useful.
Demo on CodePen: http://codepen.io/terabaud/details/PZdaJo/
I found one solution for SVG. But it is work only for Webkit, I just want share my workaround with you. In my example is shown how to use SVG element from DOM as background through a filter (background-image: url('#glyph') is not working).
Features needed for this SVG icon render:
Applying SVG filter effects to HTML elements using CSS (IE and
Edge not supports)
feImage fragment load supporting (firefox not
supports)
.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>
One more solution, is use 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>
Inline SVG coming from 3rd party sources (like Google charts) may not contain XML namespace attribute (xmlns="http://www.w3.org/2000/svg") in SVG element (or maybe it's removed once SVG is rendered - neither browser inspector nor jQuery commands from browser console show the namespace in SVG element).
When you need to re-purpose these svg snippets for your other needs (background-image in CSS or img element in HTML) watch out for the missing namespace. Without the namespace browsers may refuse to display SVG (regardless of the encoding utf8 or base64).
If you're using postcss you can try the postcss-inline-svg plugin https://www.npmjs.com/package/postcss-inline-svg
.up {
background: svg-load('img/arrow-up.svg', fill: #000, stroke: #fff);
}
.down {
background: svg-load('img/arrow-down.svg', fill=#000, stroke=#fff);
}
Done programatically based on the approach taken by the already mentioned https://github.com/yoksel/url-encoder/ :
// Svg (string)
const hexagon = `
<svg
width="100"
height="20"
viewBox="0 0 100 20"
xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient
id="redyel"
gradientUnits="objectBoundingBox"
x1="0"
y1="0"
x2="1"
y2="1"
>
<stop offset="0%" stop-color="#ff0000" />
<stop offset="100%" stop-color="#ffff00" />
</linearGradient>
</defs>
<polygon
points="0,10 5,0 95,0 100,10 95,20 5,20"
fill="#eee"
stroke="url(#redyel)"
/>
</svg>
`
// svgToBackgroundImage
const symbols = /[%#()<>?[\\\]^`{|}]/g;
const newLine = /\r?\n/;
const notEmptyString = (str) => str.length;
const trim = (str) => str.trim();
const toOneLine = (str) =>
str.split(newLine).filter(notEmptyString).map(trim).join(" ");
function addNameSpace(svgString) {
if (svgString.indexOf(`http://www.w3.org/2000/svg`) < 0) {
svgString = svgString.replace(
/<svg/g,
`<svg xmlns="http://www.w3.org/2000/svg"`
);
}
return svgString;
}
function encodeSVG(svgString) {
svgString = svgString.replace(/>\s{1,}</g, `><`);
svgString = svgString.replace(/\s{2,}/g, ` `);
// Using encodeURIComponent() as replacement function
// allows to keep result code readable
return svgString.replace(symbols, encodeURIComponent);
}
const svgToBackgroundImage = (svgString) =>
`url('data:image/svg+xml,${encodeSVG(addNameSpace(toOneLine(svgString)))}')`;
// DOM
const element = document.querySelector("#hexagon");
element.style.backgroundImage = svgToBackgroundImage(hexagon);
#hexagon {
width: 100px;
height: 20px;
}
<div id="hexagon"/>
You can also just do this:
<svg viewBox="0 0 32 32">
<path d="M11.333 13.173c0-2.51 2.185-4.506 4.794-4.506 2.67 0 4.539 2.053 4.539 4.506 0 2.111-0.928 3.879-3.836 4.392v0.628c0 0.628-0.496 1.141-1.163 1.141s-1.163-0.513-1.163-1.141v-1.654c0-0.628 0.751-1.141 1.419-1.141 1.335 0 2.571-1.027 2.571-2.224 0-1.255-1.092-2.224-2.367-2.224-1.335 0-2.367 1.027-2.367 2.224 0 0.628-0.546 1.141-1.214 1.141s-1.214-0.513-1.214-1.141zM15.333 23.333c-0.347 0-0.679-0.143-0.936-0.404s-0.398-0.597-0.398-0.949 0.141-0.689 0.398-0.949c0.481-0.488 1.39-0.488 1.871 0 0.257 0.26 0.398 0.597 0.398 0.949s-0.141 0.689-0.398 0.949c-0.256 0.26-0.588 0.404-0.935 0.404zM16 26.951c-6.040 0-10.951-4.911-10.951-10.951s4.911-10.951 10.951-10.951c6.040 0 10.951 4.911 10.951 10.951s-4.911 10.951-10.951 10.951zM16 3.333c-6.984 0-12.667 5.683-12.667 12.667s5.683 12.667 12.667 12.667c6.984 0 12.667-5.683 12.667-12.667s-5.683-12.667-12.667-12.667z"></path>
</svg>