Clip path not displaying properly in SVG sprite when using "use" - svg

I'm trying to hack together a sprite sheet from a set of icons. I know almost nothing about SVG. I can get the simple icons to work, but an icon with a clip path isn't displaying properly. From what I can tell it seems like it's not using the clip path.
The sprite works in jsfilddle and it works if I just load the svg on it's own and include a < use > statement in the SVG. But if I have a separate < use > it doesn't work.
All my testing has been done in Chrome (50.0.2661.94)
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<clipPath id="folder-clip-0">
<path d="..." />
</clipPath>
<symbol id="folder" viewBox="0 0 32 32">
<g class="container" data-width="32" data-height="27" transform="translate(0 2)">
<path d="..." class="..." />
<path class="..." d="..." />
<path clip-path="url(#folder-clip-0)" d="..." class="..." />
</g>
</symbol>
</defs>
</svg>
I'm using it like so:
<svg>
<use
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="/img/path/sprite.svg#folder">
</use>
</svg>
When I use the separate statement it looks like this:
But it should look like this:
The color difference is not relevant, it's just the background when the image was taken.
Edit:
I just discovered that if I dump the whole sprite sheet into the page HTML and reference it locally instead of an external file it works. So I don't know what's wrong with my external reference.
e.g.
<svg>
<use xlinkHref={"/img/path/not/work/sprite.svg#folder"}></use>
</svg>
vs.
<svg>
<symbol id="folder"></symbol>
</svg>
<svg>
<use xlinkHref={"#folder"}></use>
</svg>
This works for me as a fallback, but I'd rather have an external SVG file instead of embedding it in my HTML.
Edit 2:
If the SVG sprite sheet is embeded in the HTML directly using the external link shows the icon correctly.

This seems to be a browser support issue. Using the external reference works as expected in Firefox. Chrome doesn't handle clip paths and some other functions in external references. There's an outstanding bug report filed. Safari also doesn't support it.
Related StackOverflow ticket: Why can't I reference an SVG linear gradient defined in an external file (paint server)?
Open bugs:
https://code.google.com/p/chromium/issues/detail?id=109212
https://bugs.webkit.org/show_bug.cgi?id=105904

Related

Images in nested <defs> do not show up in chromium

I have some SVG files whereby one includes the other by using <use /> elements. To merge all those files into one resulting one, I have written some code that transforms ./main.svg from below:
#file: ./svg/shared.svg
<svg>
<image xlink:href="../img/bg.png" id="bg" />
</svg>
#file: ./svg/index.svg
<svg id="index">
<use xlink:href="./shared.svg#bg" />
</svg>
#file: ./main.svg
<svg>
<use xlink:href="./svg/index.svg#index" />
</svg>
into:
<svg>
<defs>
<svg id="svg-index">
<defs>
<image xlink:href="./img/bg.png" id="img-bg" />
</defs>
<use xlink:href="#img-bg" />
</svg>
</defs>
<use xlink:href="#svg-index" />
</svg>
So basically all urls and Ids are resolved and referenced nodes are imported. The script works fine, in Firefox and the result works as well in Inkscape. BUT in chromium the images do not show up. They are loaded, what I can see from the networking tab.
If I modify the images' xlink:href (inspector panel) by adding a little #qwertz at the end of one image, all of them show up, so that seams to be browser related, since the result works in FF and Inkscape.
Any Idea how to fix that?
UPDATE
One thing that may have some effect here is whether the manipulated SVG is already inserted into the dom or not. So this code makes the images appear:
setTimeout(function () {
[...document.querySelectorAll('image')].forEach(
img => img.setAttribute('xlink:href',
img.getAttribute('xlink:href')
)
);
}, 0)
But that feels really hackish and I am really interested in a »cleaner« solution here…

svg image element not shown on mobile

I have been trying to get the cross browser compatability working of my svg project. I had a friend test my link on a mobile, but he sais the image doesn't load and he gets a black screen (I assume the black he refers too, is the rect in the background). Does anyone have any idea what is wrong with my code or why the image doesn't display properly on mobile?
svg
<svg viewbox="0 0 3000 2500">
<g transform="translate(225,50)">
<rect width="2550" height="1925" id="background-rect"></rect>
<image href="http://lorempixel.com/output/animals-q-c-640-480-3.jpg" width="2550" height="1925"></image>
</g>
</svg>
Example: https://codepen.io/RobMo/pen/aVvKEP
PS: Just an idea: It might have to do with me not declaring a namespace. I can't test it right now, but that might be what is causing this. Or maybe help people provide inspiration for an answer :).
PPS: To use the <img> tag you need to use xlink:href instead of just href. I should've decared the namespace in the svg tag as well.
What happens when you add a namespace?
<svg viewbox="0 0 3000 2500" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(225,50)">
<rect width="2550" height="1925" id="background-rect"></rect>
<image href="http://lorempixel.com/output/animals-q-c-640-480-3.jpg" width="2550" height="1925"></image>
</g>
</svg>
REF - https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image

SVG <defs> not included from external target of <use> [duplicate]

I'm trying to hack together a sprite sheet from a set of icons. I know almost nothing about SVG. I can get the simple icons to work, but an icon with a clip path isn't displaying properly. From what I can tell it seems like it's not using the clip path.
The sprite works in jsfilddle and it works if I just load the svg on it's own and include a < use > statement in the SVG. But if I have a separate < use > it doesn't work.
All my testing has been done in Chrome (50.0.2661.94)
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<clipPath id="folder-clip-0">
<path d="..." />
</clipPath>
<symbol id="folder" viewBox="0 0 32 32">
<g class="container" data-width="32" data-height="27" transform="translate(0 2)">
<path d="..." class="..." />
<path class="..." d="..." />
<path clip-path="url(#folder-clip-0)" d="..." class="..." />
</g>
</symbol>
</defs>
</svg>
I'm using it like so:
<svg>
<use
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="/img/path/sprite.svg#folder">
</use>
</svg>
When I use the separate statement it looks like this:
But it should look like this:
The color difference is not relevant, it's just the background when the image was taken.
Edit:
I just discovered that if I dump the whole sprite sheet into the page HTML and reference it locally instead of an external file it works. So I don't know what's wrong with my external reference.
e.g.
<svg>
<use xlinkHref={"/img/path/not/work/sprite.svg#folder"}></use>
</svg>
vs.
<svg>
<symbol id="folder"></symbol>
</svg>
<svg>
<use xlinkHref={"#folder"}></use>
</svg>
This works for me as a fallback, but I'd rather have an external SVG file instead of embedding it in my HTML.
Edit 2:
If the SVG sprite sheet is embeded in the HTML directly using the external link shows the icon correctly.
This seems to be a browser support issue. Using the external reference works as expected in Firefox. Chrome doesn't handle clip paths and some other functions in external references. There's an outstanding bug report filed. Safari also doesn't support it.
Related StackOverflow ticket: Why can't I reference an SVG linear gradient defined in an external file (paint server)?
Open bugs:
https://code.google.com/p/chromium/issues/detail?id=109212
https://bugs.webkit.org/show_bug.cgi?id=105904

Responsive SVG sprites

I am building an icon system for a site and moving away from png and font-icon sprites to SVG.
I need it to work across all major browsers (IE9+) and ideally want to use fragment identifiers or, as a second best alternative, inline. I've done extensive research, and there isn't a great deal out there, and from what I have read SVG sprites aren't particularly responsive.
For fragment identifiers, using img tag, I have to set the width/height to the same size as the viewbox. Increasing the dimensions on the img tag ends up revealing some of the next sprite. I'd like to be able to use percentage values so the sprite fragment fills the parent container.
I just want confirmation that this isn't possible, I can't find anything that suggests I am wrong to think this.
This is very much possible and is relatively easy to accomplish. SVG's are vector graphics and therefore, if done correctly, will be the most responsive graphics on your website.
Set your SVG file up as expected but put each sprite into a <g> tag with its own identifier.
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g class="sprite" id="circle">
<ellipse cy="50" cx="50" ry="45" rx="45" stroke-width="5" stroke="#00ff00" fill="#00ff00" fill-opacity="0.75" />
</g>
<g class="sprite" id="square">
<rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#ff0000" fill="#ff0000" fill-opacity="0.75" />
</g>
<g class="sprite" id="triangle">
<path d="M20,7 L92,50 L6,93 z" stroke-width="5" stroke="#0000ff" fill="#0000ff" fill-opacity="0.75" />
</g>
</svg>
Add some CSS to say only the rargeted one needs to be displayed
<defs>
<style><![CDATA[
.sprite { display: none; }
.sprite:target { display: inline; }
]]></style>
</defs>
Then you can just call these out whenever required using an img tag or background element etc.
You can find the fully explained writeup here:
How to Use SVG Image Sprites

Can you combine multiple svgs with different viewBoxes and customize each in Polymer?

I have multiple svgs that I'd like to use in my application and was hoping to put them in a single custom-svg element to reference individually by id, however, the viewBoxes are different. One svg is defined as
<iron-iconset-svg name="club-icon" size="512">
<svg>
<defs>
<g id="club-icon">
<path d="bunch of numbers"></path>
</g>
</defs>
</svg>
</iron-iconset-svg>
The other svg is defined as
<iron-iconset-svg name="club-icon" size="300">
<svg>
<defs>
<g id="book-icon">
<path d="bunch of numbers"></path>
</g>
</defs>
</svg>
</iron-iconset-svg>
Is there a way for each custom icon to define its own viewBox, or must every svg defined within a single iconset share the same properties. For now I have multiple custom element html files, but each custom element is an http request (which I'm trying to minimize).
It can be done using symbols.
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="beaker" viewBox="214.7 0 182.6 792">
<!-- <path>s and whatever other shapes in here -->
</symbol>
<symbol id="shape-icon-2" viewBox="0 26 100 48">
<!-- <path>s and whatever other shapes in here -->
</symbol>
</svg>
See this article on CSS tricks for a further explanation.
https://css-tricks.com/svg-symbol-good-choice-icons/
you might try a transform scale on you g element?
<g id="book-icon" transform="scale(1.71)">
1.71 = 512/300
or if you are using gulp/grunt, you could resize the SVGs to be the same using svg-scaler or the like

Resources