html
<img src="logo.svg" alt="Logo" class="logo-img">
css
.logo-img path {
fill: #000;
}
The above svg loads and is natively fill: #fff but when I use the above css to try change it to black it doesn't change, this is my first time playing with SVG and I am not sure why it's not working.
You could set your SVG as a mask. That way setting a background-color would act as your fill color.
HTML
<div class="logo"></div>
CSS
.logo {
background-color: red;
-webkit-mask: url(logo.svg) no-repeat center;
mask: url(logo.svg) no-repeat center;
}
JSFiddle: https://jsfiddle.net/KuhlTime/2j8exgcb/
MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/mask
Please check whether your browser supports this feature:
https://caniuse.com/#search=mask
If your goal is just to change the color of the logo, and you don't necessarily NEED to use CSS, then don't use javascript or jquery as was suggested by some previous answers.
To precisely answer the original question, just:
Open your logo.svg in a text editor.
look for fill: #fff and replace it with fill: #000
For example, your logo.svg might look like this when opened in a text editor:
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" fill="#fff"/>
</svg>
... just change the fill and save.
Try pure CSS:
.logo-img {
/* to black */
filter: invert(1);
/* or to blue */
filter: invert(0.5) sepia(1) saturate(5) hue-rotate(175deg);
}
more info in this article https://blog.union.io/code/2017/08/10/img-svg-fill/
If you want a dynamic color, do not want to use javascript and do not want an inline SVG, use a CSS variable. Works in Chrome, Firefox and Safari. edit: and Edge
<svg>
<use href="logo.svg" style="--color_fill: #000;"></use>
</svg>
In your SVG, replace any instances of style="fill: #000" with style="fill: var(--color_fill)".
You will first have to inject the SVG into the HTML DOM.
There is an open source library called SVGInject that does this for you. It uses the onload attribute to trigger the injection.
Here is a minimal example using SVGInject:
<html>
<head>
<script src="svg-inject.min.js"></script>
</head>
<body>
<img src="image.svg" onload="SVGInject(this)" />
</body>
</html>
After the image is loaded the onload="SVGInject(this) will trigger the injection and the <img> element will be replaced by the contents of the SVG file provided in the src attribute.
It solves several issues with SVG injection:
SVGs can be hidden until injection has finished. This is important if a style is already applied during load time, which would otherwise cause a brief "unstyled content flash".
The <img> elements inject themselves automatically. If you add SVGs dynamically, you don't have to worry about calling the injection function again.
A random string is added to each ID in the SVG to avoid having the same ID multiple times in the document if an SVG is injected more than once.
SVGInject is plain Javascript and works with all browsers that support SVG.
Disclaimer: I am the co-author of SVGInject
Edit your SVG file, add fill="currentColor" to svg tag and make sure to remove any other fill property from the file.
For example:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 139.435269383854" id="img" fill="currentColor">...
</svg>
Note that currentColor is a keyword (not a fixed color in use).
After that, you can change the color using CSS, by setting the color property of the element or from it's parent.
Example:
.div-with-svg-inside {
color: red;
}
I forgot to say, you must insert the SVG this way:
<svg>
<use xlink:href='/assets/file.svg#img' href="/assets/file.svg#img"></use>
</svg>
if image is coming from some variable then
<svg>
<use [attr.xlink:href]="somevariable + '#img'" [attr.href]="somevariable + '#img'"></use>
</svg>
Note that `#img` is the id of the `svg` tag inside svg file. Also note `xlink:href` has been deprecated instead you should use `href` or use can use both to support older browser versions.
Another way of doing it: [https://css-tricks.com/cascading-svg-fill-color/][1]
[1]: https://css-tricks.com/cascading-svg-fill-color/
I suggest to select your color , and go to this pen
https://codepen.io/sosuke/pen/Pjoqqp
it will convert HEX to css filter eg:#64D7D6
equal
filter: invert(88%) sepia(21%) saturate(935%) hue-rotate(123deg) brightness(85%) contrast(97%);
the final snippet
.filterit{
width:270px;
filter: invert(88%) sepia(21%) saturate(935%) hue-rotate(123deg) brightness(85%) contrast(97%);
}
<img src="https://www.flaticon.com/svg/static/icons/svg/1389/1389029.svg"
class="filterit
/>
This answer is based on answer https://stackoverflow.com/a/24933495/3890888 but with a plain JavaScript version of the script used there.
You need to make the SVG to be an inline SVG. You can make use of this script, by adding a class svg to the image:
/*
* Replace all SVG images with inline SVG
*/
document.querySelectorAll('img.svg').forEach(function(img){
var imgID = img.id;
var imgClass = img.className;
var imgURL = img.src;
fetch(imgURL).then(function(response) {
return response.text();
}).then(function(text){
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(text, "text/xml");
// Get the SVG tag, ignore the rest
var svg = xmlDoc.getElementsByTagName('svg')[0];
// Add replaced image's ID to the new SVG
if(typeof imgID !== 'undefined') {
svg.setAttribute('id', imgID);
}
// Add replaced image's classes to the new SVG
if(typeof imgClass !== 'undefined') {
svg.setAttribute('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http://validator.w3.org
svg.removeAttribute('xmlns:a');
// Check if the viewport is set, if the viewport is not set the SVG wont't scale.
if(!svg.getAttribute('viewBox') && svg.getAttribute('height') && svg.getAttribute('width')) {
svg.setAttribute('viewBox', '0 0 ' + svg.getAttribute('height') + ' ' + svg.getAttribute('width'))
}
// Replace image with new SVG
img.parentNode.replaceChild(svg, img);
});
});
And then, now if you do:
.logo-img path {
fill: #000;
}
Or may be:
.logo-img path {
background-color: #000;
}
JSFiddle: http://jsfiddle.net/erxu0dzz/1/
Use filters to transform to any color.
I recently found this solution, and hope somebody might be able to use it.
Since the solution uses filters, it can be used with any type of image. Not just svg.
If you have a single-color image that you just want to change the color of, you can do this with the help of some filters. It works on multicolor images as well of course, but you can't target a specific color. Only the whole image.
The filters came from the script proposed in How to transform black into any given color using only CSS filters
If you want to change white to any color, you can adjust the invert value in each filter.
.startAsBlack{
display: inline-block;
width: 50px;
height: 50px;
background: black;
}
.black-green{
filter: invert(43%) sepia(96%) saturate(1237%) hue-rotate(88deg) brightness(128%) contrast(119%);
}
.black-red{
filter: invert(37%) sepia(93%) saturate(7471%) hue-rotate(356deg) brightness(91%) contrast(135%);
}
.black-blue{
filter: invert(12%) sepia(83%) saturate(5841%) hue-rotate(244deg) brightness(87%) contrast(153%);
}
.black-purple{
filter: invert(18%) sepia(98%) saturate(2657%) hue-rotate(289deg) brightness(121%) contrast(140%);
}
Black to any color: <br/>
<div class="startAsBlack black-green"></div>
<div class="startAsBlack black-red"></div>
<div class="startAsBlack black-blue"></div>
<div class="startAsBlack black-purple"></div>
Why not create a webfont with your svg image or images, import the webfont in the css and then just change the color of the glyph using the css color attribute?
No javascript needed
Simple..
You can use this code:
<svg class="logo">
<use xlink:href="../../static/icons/logo.svg#Capa_1"></use>
</svg>
First specify the path of svg and then write it's ID, In this case "Capa_1". You can get the ID of svg by opening it in any editor.
In css:
.logo {
fill: red;
}
The answer from #Praveen is solid.
I couldn't get it to respond in my work, so I made a jquery hover function for it.
CSS
.svg path {
transition:0.3s all !important;
}
JS / JQuery
// code from above wrapped into a function
replaceSVG();
// hover function
// hover over an element, and find the SVG that you want to change
$('.element').hover(function() {
var el = $(this);
var svg = el.find('svg path');
svg.attr('fill', '#CCC');
}, function() {
var el = $(this);
var svg = el.find('svg path');
svg.attr('fill', '#3A3A3A');
});
If you are just switching the image between the real color and the black-and-white, you can set one selector as:
{filter:none;}
and another as:
{filter:grayscale(100%);}
To expand on #gringo answer, the Javascript method described in other answers works, but requires the user to download unnecessary image files, and IMO, it bloats your code.
I think a better approach would be to to migrate all 1-color vector graphics to a webfont file. I've used Fort Awesome in the past, and it works great to combine your custom icons/images in SVG format, along with any 3rd party icons you may be using (Font Awesome, Bootstrap icons, etc.) into a single webfont file the user has to download. You can also customize it, so you only include the 3rd party icons you're using. This reduces the number of requests the page has to make, and you're overall page weight, especially if you're already including any 3rd party icons libraries.
If you prefer a more dev oriented option, you could Google "npm svg webfont", and use one of the node modules that's most appropriate for your environment.
Once, you've done either of those two options, then you could easily change the color via CSS, and most likely, you've sped up your site in the process.
Since SVG is basically code, you need just contents. I used PHP to obtain content, but you can use whatever you want.
<?php
$content = file_get_contents($pathToSVG);
?>
Then, I've printed content "as is" inside a div container
<div class="fill-class"><?php echo $content;?></div>
To finnaly set rule to container's SVG childs on CSS
.fill-class > svg {
fill: orange;
}
I got this results with a material icon SVG:
Mozilla Firefox 59.0.2 (64-bit) Linux
Google Chrome66.0.3359.181 (Build oficial) (64 bits) Linux
Opera 53.0.2907.37 Linux
The main problem in your case is that you are importing the svg from an <img> tag which will hide the SVG structure.
You need to use the <svg> tag in conjunction with the <use> to get the desired effect. To make it work, you need to give an id to the path you want to use in the SVG file <path id='myName'...> to then be able to retrieve them from the <use xlink:href="#myName"/> tag.
Try the snipped below.
.icon {
display: inline-block;
width: 2em;
height: 2em;
transition: .5s;
fill: currentColor;
stroke-width: 5;
}
.icon:hover {
fill: rgba(255,255,255,0);
stroke: black;
stroke-width: 2;
}
.red {
color: red;
}
.blue {
color: blue;
}
<svg width="0" height="0">
<defs>
<path id="home" d="M100 59.375l-18.75-18.75v-28.125h-12.5v15.625l-18.75-18.75-50 50v3.125h12.5v31.25h31.25v-18.75h12.5v18.75h31.25v-31.25h12.5z"/>
</svg>
<span class="icon red">
<svg viewbox="0 0 100 100">
<use xlink:href="#home"/>
</svg>
</span>
<span class="icon blue">
<svg viewbox="0 0 100 100">
<use xlink:href="#home"/>
</svg>
</span>
Note that you can put any URL before the fragment # if you want to load the SVG from an external source (and not embed it into your HTML). Also, usually you do not specify the fill into the CSS. It's better to consider using fill:"currentColor" within the SVG itself. The corresponding element's CSS color value will then be used in place.
This might be helpful for people using PHP in combination with .svg images that they want to manipulate with CSS.
You can't overwrite properties inside a img tag with CSS. But when the svg source code is embedded in the HTML you surely can. I like to resolve this issue with a require_once function where I include a .svg.php file. It's like importing an image but you can still overwrite styles with CSS!
First include the svg file:
<?php require_once( '/assets/images/my-icon.svg.php' ); ?>
And it includes this icon for example:
<svg xmlns="http://www.w3.org/2000/svg" width="20.666" height="59.084" viewBox="0 0 20.666 59.084"><g transform="translate(-639.749 -3139)"><path d="M648.536,3173.876c0-2.875-1.725-3.8-3.471-3.8-1.683,0-3.49.9-3.49,3.8,0,3,1.786,3.8,3.49,3.8C646.811,3177.676,648.536,3176.769,648.536,3173.876Zm-3.471,2.341c-.883,0-1.437-.513-1.437-2.341,0-1.971.615-2.381,1.437-2.381.862,0,1.438.349,1.438,2.381,0,1.907-.616,2.339-1.438,2.339Z" fill="#142312"/><path d="M653.471,3170.076a1.565,1.565,0,0,0-1.416.9l-6.558,13.888h1.2a1.565,1.565,0,0,0,1.416-.9l6.559-13.887Z" fill="#142312"/><path d="M655.107,3177.263c-1.684,0-3.471.9-3.471,3.8,0,3,1.766,3.8,3.471,3.8,1.745,0,3.49-.9,3.49-3.8C658.6,3178.186,656.851,3177.263,655.107,3177.263Zm0,6.139c-.884,0-1.438-.514-1.438-2.34,0-1.972.617-2.381,1.438-2.381.862,0,1.437.349,1.437,2.381,0,1.909-.616,2.34-1.437,2.34Z" fill="#142312"/><path d="M656.263,3159.023l-1.49-14.063a1.35,1.35,0,0,0,.329-.293,1.319,1.319,0,0,0,.268-1.123l-.753-3.49a1.328,1.328,0,0,0-1.306-1.054h-6.448a1.336,1.336,0,0,0-1.311,1.068l-.71,3.493a1.344,1.344,0,0,0,.276,1.112,1.532,1.532,0,0,0,.283.262l-1.489,14.087c-1.7,1.727-4.153,4.871-4.153,8.638v28.924a1.339,1.339,0,0,0,1.168,1.49,1.357,1.357,0,0,0,.17.01h17.981a1.366,1.366,0,0,0,1.337-1.366v-29.059C660.414,3163.893,657.963,3160.749,656.263,3159.023Zm-8.307-17.349h4.274l.176.815H647.79Zm9.785,43.634v10.1H642.434v-17.253a4.728,4.728,0,0,1-2.028-4.284,4.661,4.661,0,0,1,2.028-4.215v-2c0-3.162,2.581-5.986,3.687-7.059a1.356,1.356,0,0,0,.4-.819l1.542-14.614H652.1l1.545,14.618a1.362,1.362,0,0,0,.4.819c1.109,1.072,3.688,3.9,3.688,7.059v9.153a5.457,5.457,0,0,1,0,8.5Z" fill="#142312"/></g></svg>
Now we can easily change the fill color like this with CSS:
svg path {
fill: blue;
}
I first tried to solve this problem with file_get_contents() but the solution above is much faster.
open the svg icon in your code editor and add a class after the path tag:
<path class'colorToChange' ...
You can add class to svg and change the color like this:
codepen
Know this is an old question but recently we came across the same issue, and we solved it from the server side. This is a php specific answer but I am positive that other envs have something similar.
instead of using the img tag you render the svg as svg from the get-go.
public static function print_svg($file){
$iconfile = new \DOMDocument();
$iconfile->load($file);
$tag = $iconfile->saveHTML($iconfile->getElementsByTagName('svg')[0]);
return $tag;
}
now when you render the file you will get complete inline svg
For me, my svgs looked different when having them as img and svg. So my solution converts the img to csv, changes styles internally and back to img (although it requires a bit more work), I believe "blob" also has better compatibility than the upvoted answer using "mask".
let img = yourimgs[0];
if (img.src.includes(".svg")) {
var ajax = new XMLHttpRequest();
ajax.open("GET", img.src, true);
ajax.send();
ajax.onload = function (e) {
svg = e.target.responseText;
svgText = "";
//change your svg-string as youd like, for example
// replacing the hex color between "{fill:" and ";"
idx = svg.indexOf("{fill:");
substr = svg.substr(idx + 6);
str1 = svg.substr(0, idx + 6);
str2 = substr.substr(substr.indexOf(";"));
svgText = str1 + "#ff0000" + str2;
let blob = new Blob([svgText], { type: "image/svg+xml" });
let url = URL.createObjectURL(blob);
let image = document.createElement("img");
image.src = url;
image.addEventListener("load", () => URL.revokeObjectURL(url), {
once: true,
});
img.replaceWith(image);
};
}
Simple JS
Use following short function ImgToSvg which swap img to svg (including class list)
<img src="logo.svg" onload="ImgToSvg(this)" class="logo-img"/>
const ImgToSvg= async (img) => {
const s = document.createElement('div');
s.innerHTML = await (await fetch(img.src)).text();
s.firstChild.classList = img.classList;
img.replaceWith(s.firstChild)
}
.logo-img {
fill: yellow;
}
<img onload="ImgToSvg(this)" class="logo-img" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMjk2IiBoZWlnaHQ9IjI5NiIgc3R5bGU9InN0cm9rZTojNTU1NTU1O3N0cm9rZS13aWR0aDoyIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtc2l6ZT0iMTgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGFsaWdubWVudC1iYXNlbGluZT0ibWlkZGxlIiBmb250LWZhbWlseT0ibW9ub3NwYWNlLCBzYW5zLXNlcmlmIiBmaWxsPSIjNTU1NTU1Ij4zMDAmIzIxNTszMDA8L3RleHQ+PC9zdmc+" />
<!-- in this snippet I use dataURI in img src to avoid CORS problems witch reading svg data from external source by js -->
This is improvement of Waruyama answer by providing short js function
I wanted to change specific paths and/or colors only and even colorize paths differently. Also, in my case some CSS was applied to the IMG-tag directly, hence I wanted to let it be original IMG-element to not mess around with positioning and alignment.
Thanks to inspiration from this answer: https://stackoverflow.com/a/43015413/1444589, this is what worked for me:
let img = document.querySelector('img[class^="YourClassName"]');
let imgURL = img.src;
fetch(imgURL)
.then(response => response.text())
.then(text => {
let parser = new DOMParser();
let xmlDoc = parser.parseFromString(text, 'text/xml');
let svg = xmlDoc.getElementsByTagName('svg')[0];
let paths = xmlDoc.getElementsByTagName('path');
// access individual path elements directly
let leftShape = paths[0];
leftShape.setAttribute('fill', '#4F4F4F');
// or find specific color
const pathsArr = Array.from(paths);
let skirtShape = pathsArr.find(path => path.getAttribute('fill') === '#F038A5');
skirtShape.setAttribute('fill', '#0078D6');
// Replace old SVG with colorized SVG
// positioning and alignment is left untouched
let base64Str = btoa(new XMLSerializer().serializeToString(svg));
img.src = 'data:image/svg+xml;base64, ' + base64Str;
});
Why not just using CSS's filter property to manipulate the color on :hover or whatever other state? I found it works over SVG images into img tags. At least, it's almost fully supported in 2020. It seams to me the simpliest solution. The only caveat is having to tweak the filter properties in order to find the target color. But you have also this very useful tool.
for that matters you have to use your SVG as an inline HTML.
say here's your logo.svg code (when you open it on textEditor):
Logo.SVG
<svg width="139" height="100" xmlns="http://www.w3.org/2000/svg">
<!-- Note that I've Added Class Attribute 'logo-img' Here -->
<g transform="translate(-22 -45)" fill="none" fill-rule="evenodd">
<path
d="M158.023 48.118a7.625 7.625 0 01-.266 10.78l-88.11 83.875a7.625 7.625 0 01-10.995-.5l-33.89-38.712a7.625 7.625 0 0111.475-10.045l28.653 32.73 82.353-78.394a7.625 7.625 0 0110.78.266z"
fill="#00000" />
</g>
</svg>
add your desired Class/ID to it (i've added 'logo-img'):
Edited Svg
<svg class="logo-img" width="139" height="100" xmlns="http://www.w3.org/2000/svg">
<!-- Note that I've Added Class Attribute 'logo-img' Here -->
...
</svg>
Now apply Your Css Rules:
CSS
.logo-img path {
fill: #000;
}
Pro
With this way you can animate on user's actions (hover, selected,...)
Con
Your HTML File would be a mess.
Heres a Stack Snippet
<style>
body {
display: flex;
justify-content: center;
}
.logo-img path {
transition: .5s all linear;
}
.logo-img path {
fill: coral;
}
.logo-img:hover path{
fill: darkblue;
}
</style>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<svg class="logo-img" width="139" height="100" xmlns="http://www.w3.org/2000/svg">
<!-- Note that I've Added Class Attribute 'logo-img' Here -->
<g transform="translate(-22 -45)" fill="none" fill-rule="evenodd">
<path
d="M158.023 48.118a7.625 7.625 0 01-.266 10.78l-88.11 83.875a7.625 7.625 0 01-10.995-.5l-33.89-38.712a7.625 7.625 0 0111.475-10.045l28.653 32.73 82.353-78.394a7.625 7.625 0 0110.78.266z"
fill="#00000" />
</g>
</svg>
</body>
</html>
If your shape(s) are always one solid color and you have more than a couple, you can use Fontello and make a custom icon font with a whole series of your own custom SVG shapes. Then you can set/animate the size and color of all of them with CSS alone.
For all the possible use cases for this question, this is an essential paradigm to consider. I've used it in many projects. In any case, if you haven't heard of Fontello, you need to find out about it. If you know of a similar solution that is better, I would love to know.
Possible downfalls:
Icon/shape fonts are known to mess with screen readers, so that may take some handling.
Fontello can be finicky with importing shapes, and it may take some trial and error with authoring and exporting them.
Avoid any and all grouping, and use only single non-nested compound shapes.
Directly to svg fill css will not work you can use as below
<style>
svg path {
fill: red;
}
</style>
<svg xmlns="http://www.w3.org/2000/svg" width="20.666" height="59.084" viewBox="0 0 20.666 59.084"><g transform="translate(-639.749 -3139)"><path d="M648.536,3173.876c0-2.875-1.725-3.8-3.471-3.8-1.683,0-3.49.9-3.49,3.8,0,3,1.786,3.8,3.49,3.8C646.811,3177.676,648.536,3176.769,648.536,3173.876Zm-3.471,2.341c-.883,0-1.437-.513-1.437-2.341,0-1.971.615-2.381,1.437-2.381.862,0,1.438.349,1.438,2.381,0,1.907-.616,2.339-1.438,2.339Z" fill="#142312"/><path d="M653.471,3170.076a1.565,1.565,0,0,0-1.416.9l-6.558,13.888h1.2a1.565,1.565,0,0,0,1.416-.9l6.559-13.887Z" fill="#142312"/><path d="M655.107,3177.263c-1.684,0-3.471.9-3.471,3.8,0,3,1.766,3.8,3.471,3.8,1.745,0,3.49-.9,3.49-3.8C658.6,3178.186,656.851,3177.263,655.107,3177.263Zm0,6.139c-.884,0-1.438-.514-1.438-2.34,0-1.972.617-2.381,1.438-2.381.862,0,1.437.349,1.437,2.381,0,1.909-.616,2.34-1.437,2.34Z" fill="#142312"/><path d="M656.263,3159.023l-1.49-14.063a1.35,1.35,0,0,0,.329-.293,1.319,1.319,0,0,0,.268-1.123l-.753-3.49a1.328,1.328,0,0,0-1.306-1.054h-6.448a1.336,1.336,0,0,0-1.311,1.068l-.71,3.493a1.344,1.344,0,0,0,.276,1.112,1.532,1.532,0,0,0,.283.262l-1.489,14.087c-1.7,1.727-4.153,4.871-4.153,8.638v28.924a1.339,1.339,0,0,0,1.168,1.49,1.357,1.357,0,0,0,.17.01h17.981a1.366,1.366,0,0,0,1.337-1.366v-29.059C660.414,3163.893,657.963,3160.749,656.263,3159.023Zm-8.307-17.349h4.274l.176.815H647.79Zm9.785,43.634v10.1H642.434v-17.253a4.728,4.728,0,0,1-2.028-4.284,4.661,4.661,0,0,1,2.028-4.215v-2c0-3.162,2.581-5.986,3.687-7.059a1.356,1.356,0,0,0,.4-.819l1.542-14.614H652.1l1.545,14.618a1.362,1.362,0,0,0,.4.819c1.109,1.072,3.688,3.9,3.688,7.059v9.153a5.457,5.457,0,0,1,0,8.5Z" fill="#142312"/></g></svg>
This worked for me
Related
I have an SVG file:
myIcon.svg
<svg>.....</svg>
I want to use it in my css:
.body {
background-image: url(../myIcon.svg);
}
since an svg needs to be encoded for it to work as a background-image, that leaves me with something like this:
.body {
background-image: url("data:image/svg+xml,***<here place encoded svg>***");
}
Is there a way to store the encoded svg in it's own file for maintainability? Since it's not in html tags, I'm not sure how save it to it's own file or if it's even possible.
Put some hours in investigating which characters are not allowed in a data:image/svg URI
Many encoders convert < and >, but those are valid.
Load your external SVG file and replace all invalid characters
Create a new <style> element with the background-image
Wrapped in a modern Web Component so it totally does not matter when the script is executed
⚠️ xmlns="http://www.w3.org/2000/svg" must be present in the SVG file; it is not required when you inline SVGs in modern browsers.
<svg-import-background src="//svg-cdn.github.io/red.svg" selector="#container"></svg-import-background>
<svg-import-background src="//svg-cdn.github.io/yellow.svg" selector="div > h2"></svg-import-background>
<svg-import-background src="//svg-cdn.github.io/blue.svg" selector="pre"></svg-import-background>
<style>
body { font:16px Arial; color:beige } h2 { color: black }
</style>
<div id="container">
<h2>Web Component <svg-import-background></h2>
Inject external SVG file into CSS background-image
<pre>
<svg-import-background ATTRIBUTES:
src="PATH TO SVG FILE"
selector="Element selector"
</pre>
</div>
<script>
customElements.define("svg-import-background", class extends HTMLElement {
async connectedCallback() {
let svg = await (await fetch(this.getAttribute("src"))).text();
svg = svg.replace(/\>[\t\s\n ]+\</g, "><"); // replace all BETWEEN tags
svg = svg.replace(/#/g, "%23");
svg = svg.replace(/"/g, "'");
this.innerHTML = `<style>${this.getAttribute("selector") || "body"}{`+
`background-image:url("data:image/svg+xml;charset=UTF-8,${svg}")`+
`}</style>`;
}
})
</script>
<svg viewBox="0 0 8 8"><rect width="100%" height="100%" fill="gold"></rect></svg>
Re: encodeURIComponent
Yes, you can replace all 3 replace statements with:
svg = encodeURIComponent(svg);
The difference is what is injected in your HTML code.
The 3 replace statements injects:
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><rect width='100%' height='100%' fill='%23f00'></rect></svg>
encodeURIComponent injects:
%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%208%208%22%3E%0A%20%20%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22%2300f%22%3E%3C%2Frect%3E%0A%3C%2Fsvg%3E
It is up to you which one you want to debug
I have an 'Input' with type 'search'
<input class="border01" type="search">
This gives me an search icon in my searchbar. How can I change the color of the search icon?
The screenshot shows what is generated when giving an input the type 'search". The 'background-image' is the search-icon
You can edit the color using the fill attribute of SVG. You can apply that on your path. I had to use !important for the class because it would have lower priority. I replaced it with id for CSS specificity.
input#border01 {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="red" opacity="0.45" d="M14.891,14.39l-0.5.5a0.355,0.355,0,0,1-.5,0L9.526,10.529a5.3,5.3,0,1,1,2.106-4.212,5.268,5.268,0,0,1-1.1,3.21l4.362,4.362A0.354,0.354,0,0,1,14.891,14.39ZM6.316,2.418a3.9,3.9,0,1,0,3.9,3.9A3.9,3.9,0,0,0,6.316,2.418Z"/></svg>');
}
<link href="https://raw.githack.com/Spiderpig86/Cirrus/master/dist/cirrus.min.css" rel="stylesheet"/>
<input id="border01" type="search">
The image seems to be a data:image SVG. You might need to have a different SVG file and insert it only for the search input. You could do that like this:
input[type=search] {
background-image: url("url to the other image");
}
If you would like to keep the original picture, this might help you:
Change color of PNG image via CSS?
In this case, the color of the original picture can be changed via filters.
For anyone who wants it done with JS
let input = document.querySelector('[type="search"]'); // get <input type="search">
console.log(input); // verify you got the correct input
let svg = getComputedStyle(input).backgroundImage; // get current background-image
svg = svg.replace(/\\"/g,"'"); // replace all double quotes with single quotes
svg = svg.replace("d=",`fill='red' d=`); // inject fill attribute
input.style.backgroundImage = svg; // set style (overruling CSS!)
I want to use a svg as container for a div element which should contain several elements. At the moment it looks like this:
<body>
<svg width="100%" height="100%" viewBox="0 0 45 90" version="1.1" xmlns="http://www.w3.org/2000/svg" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
<path d="M45.02,17.449l0,-5.837l-0.324,0c0,-3.841 0,-6.21 0,-6.344c0,-0.786 0.105,-3.078 -2.657,-3.659c-5.996,-1.263 -19.539,-1.352 -19.539,-1.352c0,0 -13.543,0.089 -19.539,1.352c-2.762,0.58 -2.657,2.873 -2.657,3.659c0,0.192 0,4.987 0,12.133l-0.324,0l0,14.537l0.324,0c0,22.9 0,52.313 0,52.794c0,0.786 -0.105,3.079 2.656,3.66c5.997,1.262 19.54,1.351 19.54,1.351c0,0 13.542,-0.089 19.539,-1.351c2.762,-0.581 2.657,-2.874 2.657,-3.66c0,-0.594 0,-45.159 0,-67.283l0.324,0Zm-22.52,-13.778c0.535,0 0.969,0.434 0.969,0.969c0,0.536 -0.434,0.97 -0.969,0.97c-0.535,0 -0.969,-0.435 -0.969,-0.97c0,-0.536 0.434,-0.969 0.969,-0.969Zm20.262,75.595l-40.525,0l0,-71.234l40.524,0l0,71.234l0.001,0Z" style="fill-rule:nonzero;"></path>
<foreignObject x="2.238" y="8.019" width="40" height="71">
<div id="screen">
I'm a very long text. Why am I so big?
</div>
</foreignObject>
</svg>
</body>
CSS
html, body{
width: 100%;
height: 100%;
}
#screen{
background: green;
overflow: scroll;
width: 100%;
height: 100%;
font-size: 10px;
}
JSFiddle
My problem is that all elements inside the screen-div are way larger than expected. e.g. see the scrollbar or the size of the text.
I assume the content of the foreignObject is scaled by the same factor as the svg. Is there a way to avoid this? Could I normalize the div inside the foreignObject to be not scaled or zoomed?
svg is "Smartphone" by Martin Jordan from the Noun Project
The only solution I can think of is to use JavaScript to dynamically size and counter-scale the foreignObject based on the viewBox dimensions versus the offsetWidth and offsetHeight of the outer <svg>.
For example, in this demo I happen to have hard-coded the size of the SVG to be four times as large as the viewBox dimensions. To counteract this, I made the foreignObject four times as large, but then scaled it down to one-quarter the size:
<foreignObject width="164" height="288" transform="translate(2,8) scale(0.25,0.25)">
https://jsfiddle.net/7ttps7a7/3/
A good generic solution would be to put an extra attribute in a custom namespace on any foreignObject, and then load a JavaScript library that finds such elements and dynamically adjusts them (and keeps them adjusted as the size of the SVG changes).
Note that comparing offsetWidth (and height) vs viewBox width (and height) needs to consider the value of the preserveAspectRatio attribute on the SVG to be precise.
Edit: I've created a small library that does this
Library: http://phrogz.net/SVG/fixed-size-foreignObject.js
Demo: http://phrogz.net/SVG/fixed-size-foreignObject.html
To use it:
Include the library in your HTML or SVG page.
Please download it and host it on your own site; I am not a CDN.
Be sure to use x and y attributes to place your <foreignObject>, and width and height values to size it.
Use one of the following:
fixedSizeForeignObject( someForeignObjectElement );
fixedSizeForeignObjects( arrayOfForeignObjectElements );
How it works:
When a foreignObject is added to the list of elements to keep resized, its original x, y, width, height values are recorded. The SVG element that owns the foreignObject is added to list of SVG elements to watch.
When the window resizes, code is triggered that (a) calculates the scale of each SVG (actual pixels versus viewBox size) and then (b) for each foreignObject registered it adjusts the width/height to be correct, and then scales the element down to fit in the original location.
I'll copy/paste the library here in the (unlikely) case that my site is down:
(function(win){
const svgs, els=[];
win.fixedSizeForeignObjects = function fixedSizeForeignObjects(els) {
els.forEach( fixedSizeForeignObject );
}
win.fixedSizeForeignObject = function fixedSizeForeignObject(el) {
if (!svgs) { svgs = []; win.addEventListener('resize',resizeSVGs,false) }
let svg=el.ownerSVGElement, found=false;
for (let i=svgs.length;i--;) if (svgs[i]===svg) found=true;
if (!found) svgs.push(svg);
let info = {
el:el, svg:svg,
w:el.getAttribute('width')*1, h:el.getAttribute('height')*1,
x:el.getAttribute('x')*1, y:el.getAttribute('y')*1
};
els.push(info);
el.removeAttribute('x');
el.removeAttribute('y');
calculateSVGScale(svg);
fixScale(info);
}
function resizeSVGs(evt) {
svgs.forEach(calculateSVGScale);
els.forEach(fixScale);
}
function calculateSVGScale(svg) {
let w1=svg.viewBox.animVal.width, h1=svg.viewBox.animVal.height;
if (!w1 && !h1) svg.scaleRatios = [1,1]; // No viewBox
else {
let info = win.getComputedStyle(svg);
let w2=parseFloat(info.width), h2=parseFloat(info.height);
let par=svg.preserveAspectRatio.animVal;
if (par.align===SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_NONE) {
svg.scaleRatios = [w2/w1, h2/h1];
} else {
let meet = par.meetOrSlice === SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET;
let ratio = (w1/h1 > w2/h2) != meet ? h2/h1 : w2/w1;
svg.scaleRatios = [ratio, ratio];
}
}
}
function fixScale(info) {
let s = info.svg.scaleRatios;
info.el.setAttribute('width', info.w*s[0]);
info.el.setAttribute('height',info.h*s[1]);
info.el.setAttribute('transform','translate('+info.x+','+info.y+') scale('+1/s[0]+','+1/s[1]+')');
}
})(window);
I want to have a series of the same SVG file on a page with different colours. I'm aware that the best method of getting the SVG into the page without bloating the code, and still have it externally stylable, is through the <object> tag.
Here's what I have so far:
HTML
<object type="image/svg+xml" data="images/circle.svg" class="object-circle red" >
<!-- fallback image in CSS -->
</object>
<object type="image/svg+xml" data="images/circle.svg" class="object-circle blue" >
<!-- fallback image in CSS -->
</object>
CSS
.object-circle {
height:16px;
width:16px;
}
.red .svg-circle {
fill:#f00;
}
.blue .svg-circle {
fill:#00f;
}
SVG
<?xml-stylesheet type="text/css" href="styles.css" ?>
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400">
<defs>
<style>
.svg-circle {
fill-rule: evenodd;
}
</style>
</defs>
<path class="svg-circle" d="M200,398.688A199.552,199. ..."/>
</svg>
This just doesn't work as is. I believe there's an issue with targeting the <object> tag to manipulate the SVG's fill property in the CSS.
Taking the .red selector off the style sheet and leaving the .svg-circle selector in place works as expected - turning the circle red, but I want to be able to have several on the page with different colours.
Any help much appreciated!
If I can't crack this I might just resort to an old-fashioned .png sprite sheet.
See https://css-tricks.com/using-svg/, section “Using SVG as an <object>”:
[…] if you want the CSS stuff to work, you can't use an external stylesheet or <style> on the document, you need to use a <style> element inside the SVG file itself.
So it seems that it is not possible to style SVG elements inside an object from “outside” the object via CSS.
As CBroe says, its an issue with styling an external object. You can access it via JS and change it, but I doubt thats ideal and there's issues of making sure its loaded first etc.
However, I'm not convinced this is necessarily the best method as you say, unless there are some other requirements (eg no javascript, or libs and it must be external, you can still load it via Snap load method for example then though if you support js).
You can simply use a defs/use statement. I've just used a circle for brevity, but you could have a more complex path or whatever in there.
jsfiddle
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400">
<defs>
<style>
.svg-circle {
fill-rule: evenodd;
fill: 'red';
}
</style>
<circle id="myDefsCircle" class="svg-circle" r="20" cx="100" cy="100"/>
</defs>
<use x="10" y="0" xlink:href="#myDefsCircle" style="fill:red"/>
<use x="10" y="50" xlink:href="#myDefsCircle" style="fill:blue"/>
<use x="10" y="100" xlink:href="#myDefsCircle" style="fill:green"/>
</svg>
I was in the same predicament, but realized it's simply not possible per the current spec because SVG documents exist in their own DOM separate from the main document, similar to iframes (see this answer). However, that doesn't mean we can't hack our way around this limitation for the time being.
Since SVG files are plain text files, I figured why not just render it using JavaScript (being that the question did not explicitly state that JS cannot be used). Using the SVG circle above as an example, the function would look like this:
// Render an SVG circle
// optional oStyles = { selector: style [, ...] }
function renderCircle(oStyles) {
var sId = ('svg-'+performance.now()).replace('.', ''),
sCss = '',
sSel;
if (!oStyles) oStyles = {};
for (var i in oStyles) {
// Handle group of selectors
sSel = '';
i.split(/ *, */).forEach(function(s) {
sSel += '#' + sId + ' ' + s + ',';
});
sSel = sSel.slice(0, -1);
sCss += sSel + '{' + oStyles[i] + '}';
}
return '' +
'<svg xmlns="http://www.w3.org/2000/svg" id="' + sId + '" width="40" height="40" viewBox="0 0 40 40">' +
'<style type="text/css">' +
'<![CDATA[' +
// Default styles
'#' + sId + ' .svg-circle { fill: red; }' +
// Overrides
sCss +
']]>' +
'</style>' +
'<circle class="svg-circle" r="20" cx="20" cy="20"/>' +
'</svg>';
}
document.getElementById('canvas').innerHTML = renderCircle();
document.getElementById('canvas').innerHTML += renderCircle({'.svg-circle':'fill:blue'});
<div id="canvas"></div>
This works okay for a one-off image like a logo, but if you have a bunch of SVG icons, then you should consider using an SVG icon font or SVG sprites. Here's a good guide for implementing SVGs for the web in general:
https://svgontheweb.com/
document.addEventListener("DOMContentLoaded", function() {
//attribute name
const ATTR_NAME = "data-src";
//base64 encoded brocken image icon
const ERROR_PLACEHOLDER =
"<img src='data:image/gif;base64,R0lGODlhEQATAPcAAFKyOVGxOlOxPFSyPFSzPFSyPVSyPlWyPlWyP16kTViyRFmzRVm0RV+1T2GlUGKmUWG2U2K0VGO2V2e6UmW3Wm27X3C/XWyrYHKsaXW7ZHqwbHe7dnTAYnfBcH3EcISGhIWGhIWGhYeFh4aGhoeGh4aIhY6NjpORlJOSlJSSlJSSlZWTlZiYl5qYmpuZm5ubnp6cn5+dn4SqgIqqi56eoaGfoaGhoaKho6Kio6Oio6OhpKKipKShpKSjpKSipaSjpaajpqSlqqilqKmoqaysrL+/v4TEhY/DnpLEpJTEp5vLqaXGsaDJta3FvaXKvafKv7zhs8HjuMHjucfmv8bnv6jLwrDNz7zbyrXP17bO27jP3b3V373R5MfHyMnIycrJy8rKys3MzcTL38LP3MfO3cvR3tTW09DQ1NXV19TU2dDU39jY2dra29nd2N3d397e38rlx9jr2sfQ4cjQ4czT4crT58/X58HT6cLT6sTU6MPR7cPT7MPT7cTT78vV6dba49Tc7MXT8MXT8cbU8cbU8sfU8sbV8sfV8sfU88jW8snX88rY88vY88zZ8svY9MzZ9Mza9M3a9c3b9c7b9c3b9s7b9s/c9tDc8tPe9dPf9tDd+NHe+NPf+NLf+dvg6tvi8dXh+Nbi+Nbi+dfi+djj+drk+eDg4OHg4OHh5+Xl5uLi6Orq6uzs7OTn8eXp8ers9OHq++Tr+uXs+Obs++ft++fu++Tr/OTs/OXs/Ofu/enu+eju++jv++jv/enw/O3y/fT09Pb79PP3//r6+vr6+/v9+/r7/Pn7/vv8/vz8/Pz8/f3//P7//fz9/v79//3+//7+//7//////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAARABMAAAj+AGsAEUKwIEEeLdwQk8YwxxlVqCJKVJXGBZE3yhr+6YULly1bt3Dl8gTDS5c1GXHQIcVpVC1epVraobHKFBg2xnDI6cQp1jNpu0BtqvMizKkiQ9DoFDUrGkNptDT5CaLjh48YKXT6Ooasa7NYjy59auXqVZoVOkFlWrt2kiNLoUqVgqVmxQ45lQwZOsT3UCJFixgx4kTmxF1KgxIPIsRY8SBJgL7clZSYECI+d/YUIjRIEKZf0u5GGtSHixUnTJ5gwROokSyGdyHp0ZIkggIGDTZUyaMLWjJgsbMggYBgQIEDCyrEcSYtVQ8cc7YckXCggAEDAiZMCSZNWBkUN8ZKKKEw4LqBABakFJMG54oYFTaWdABAoH4ADlCkLaPiwUgTFCzIcIEDBD6QQRTSDNOGBglgMIMJIowQwgcUlmAGM9KwksKEIZAgQkAAOw==' >";
let target = document.querySelectorAll(`[${ATTR_NAME}]`);
//unsorted list
let _filesList = [];
target.forEach(function(item) {
_filesList.push(item.getAttribute(ATTR_NAME).replace(/\\/g, "/"));
});
//sorted list
let filesList = _filesList.filter(function(item, pos) {
return _filesList.indexOf(item) == pos;
});
//ajax request
filesList.forEach(function(item) {
let ajax = new XMLHttpRequest();
ajax.open("GET", item, true);
ajax.onload = function() {
document.querySelectorAll(`[${ATTR_NAME}="${item}"]`).forEach(item => {
if (this.status >= 200 && this.status < 400) {
// Success!
item.innerHTML = this.response;
} else {
// Error!
item.innerHTML = ERROR_PLACEHOLDER;
}
});
};
ajax.send();
});
});
<div class="icon" data-src="icon.svg">
.icon path{
fill:#000;
}
Imagine we have an anchor containing an SVG icon with a hover effect and some text.
Let's assume the icon is ment to be used multiple times in various links pointing to different URLs.
the SVG should be in a separate file not inline
the link shouldn't be embeded inside the SVG file
the hover effect should work
JS and noscript fallback to PNG is fair game
Ways to embed SVG
object:
<a href="http://tomasreichmann.cz/" >
<object data="http://svgtest.tomasreichmann.cz/images/grafika.svg" type="image/svg+xml">
</object>
Link
</a>
image
<a href="http://tomasreichmann.cz/" >
<img src="http://svgtest.tomasreichmann.cz/images/grafika.svg" alt="" />
Link
</a>
Demo
http://jsfiddle.net/YZkj9/
Is this really impossible to achieve?
Is this the reason nobody uses SVGs even though it's supported since IE9?
Thank you for your time and effort, you guys are great!
SVG's can in fact be manipulated with javascript. The catch, is that SVG objects are very buggy when attempting to be selected with jQuery, so you have to use regular javascript in making your selections at least.
Let's say (like in my case) you wrap your object in a div and an href tag; it's going to look something like this:
<div id="mp3-link">
<a href="http://your-url.com">
<object type="image/svg+xml" class="mp3-svg" id="object-svg" data="your-svg-url.com"></object>
</a>
</div>
And the code that the object tag is going to spit out is going to look something like this (in my case, an MP3 downloads link).
<div id="mp3-link">
<a href="http://google.com">
<object type="image/svg+xml" class="mp3-svg" id="object-svg">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 612 792" style="enable-background:new 0 0 612 792;" xml:space="preserve">
<defs>
<style type="text/css"><![CDATA[
.fill-blue {
fill:inherit;
stroke-width:0;
}
.mp3 {
font-family:'Lato-Bold';
stroke-width:0;
}
.stroke-blue {
fill-opacity:0;
stroke:inherit;
stroke-width:inherit;
stroke-miterlimit:inherit;
}
#hover-me:hover {
stroke:#3c4147;
fill:#3c4147;
}
#hover-me {
stroke:#227AA5;
stroke-width:22;
stroke-miterlimit:10;
fill:#227AA5;
}
]]></style>
</defs>
<g id="hover-me">
<text transform="matrix(0.7813 0 0 1 216.4761 524.5479)" class="mp3 fill-blue hover-me" style="font-size:193.4593;">MP3</text>
<path class="stroke-blue hover-me" d="M377.1,560.5v79 c0,6.2-5,11.2-11.2,11.2H30.6c-6.2,0-11.2-5-11.2-11.2V153.1c0-6.2,5-11.2,11.2-11.2h235.2c6.2,0,111.3,121.2,111.3,121.2v80.7 M593.7,535.4V373.5c0-11-9-20-20-20H189.2c-11,0-20,9-20,20v161.8c0,11,9,20,20,20h384.6C584.7,555.4,593.7,546.4,593.7,535.4z"/>
<path class="page-flap fill-blue hover-me" d="M272,164.5l46.3,50.4l46.7,52.6v2.4h-93V164.5 M267,131h-18v145.1c0,9.4,7.7,17,17.2,17H388v-34.2 l-52.6-59.3l-53.9-58.7L267,131L267,131z"/>
</g>
</svg>
</object>
</a>
</div>
What we need to do, is select an inner element of the svg (in this case, "#hover-me") and attach a javascript function to it:
//this is important, as the svg tends to load a little later than the rest of the elements
window.onload=function() {
// Get the Object by ID
var theObject = document.getElementById("object-svg");
// Get the SVG document inside the Object tag
var svgDoc = theObject.contentDocument;
// Get one of the SVG items by ID;
var svgItem = svgDoc.getElementById("hover-me");
//our javascript selector
svgItem.addEventListener('click', function() {
//here, I'm using jQuery to select the parent and get the href. This is so you can see that jQuery is possible, just not for the selection portion of the code
var svgHref = $(theObject).parent().attr("href");
//now, we navigate to the external href. I chose to open in new window.
var win = window.open(svgHref, '_blank');
win.focus();
});
}; //window.onload
So now, we've created a function that will find the link that wraps the object using javascript, and then it will navigate the user to that link using jQuery.
I tried to attach a jsfiddle, but jsfiddle's don't allow you to import an object so you'll have to try this code out on an actual web page
More info in selecting SVG elements with javascript
Edit
After looking into this further, I came up with an even more optimized way to do this:
By using javascript to actually change the styling of the hover, we can then allow the svg image to operate like a normal link (right click options, status window in the lower corner, etc)
So in this case using the same svg markup and adding a class to our link
<div id="mp3-link">
//we'll call our link "a-svg"
<a href="http://your-url.com" class="a-svg">
<object type="image/svg+xml" class="mp3-svg" id="object-svg" data="your-svg-url.com"></object>
</a>
</div>
We can use this code to change the styling of the svg when the link is hovered:
window.onload=function() {
//get our link
var theA = document.getElementsByClassName("a-svg");
//loop through all of these (jQuery does this by default, but we're forced to use regular javascript
for(var i=0;i<theA.length;i++){
//when the user hovers over the link...
theA[i].addEventListener('mouseover', function() {
var thisObject = this.getElementsByClassName('mp3-svg')[0];
var svgDoc = thisObject.contentDocument;
// Get one of the SVG items by ID;
var svgItem = svgDoc.getElementById("hover-me");
//change the attributes of the svg
svgItem.setAttribute("fill", "#3c4147");
svgItem.setAttribute("stroke", "#3c4147");
});
//now revert the changes when the mouse leaves
theA[i].addEventListener('mouseleave', function() {
var thisObject = this.getElementsByClassName('mp3-svg')[0];
var svgDoc = thisObject.contentDocument;
// Get one of the SVG items by ID;
var svgItem = svgDoc.getElementById("hover-me");
svgItem.setAttribute("fill", "#227aa5");
svgItem.setAttribute("stroke", "#227aa5");
});
}
};
Lastly, we'll need a little css in order to make it so that the link is on top of the svg
.a-svg:after {
top:0;
bottom:0;
left:0;
right:0;
position:absolute;
content"";
}
#mp3-link {
position:relative;
height:140px;
width:140px;
}
Now we have a fully functional link with a hover capability for our svg image.
As you've discovered images don't support interaction and object doesn't support being used as a link. You could dig into the images if they were objects and modify the link property using the DOM or...
Use two images, one on top of the other. The image on top is what you have now, while the image on the bottom would be a static version of the hovered image i.e. edit the image you have now and change the fill so that it looks like the hovered version and save that as a separate file.
Now make the image on top transition its opacity to 0 on hover. You'll want to make the images position absolute so they sit on top of each other. Something like this...
<a href="http://tomasreichmann.cz/" >
<img src="http://svgtest.tomasreichmann.cz/images/grafika-hover.svg" alt="" />
<img class="top" src="http://svgtest.tomasreichmann.cz/images/grafika.svg" alt="" />
Link
</a>
img {
position:absolute;
left:0;
-webkit-transition: opacity 0.3s;
-moz-transition: opacity 0.3s;
-ms-transition: opacity 0.3s;
-o-transition: opacity 0.3s;
transition: opacity 0.3s;
}
img.top:hover {
opacity:0;
}