I'm building an icon solution using SVG, where parts of icons need to be reusable. There are a few different <svg /> elements inline in my HTML document, and the <use /> element works perfectly for reusing shapes – rects, paths and so on, even between svg elements.
However, reusing other definitions, like <radialGradient /> doesn't work for me. When the gradient is defined within a <defs /> element in the same <svg /> element, it works as expected, but not when the gradient is defined in another <svg /> element.
Pseudo code
<!-- Near the top of my BODY element -->
<!-- This is where I keep the SVG stuff I want to reuse -->
<svg id="for-reuse" style="display:none">
<defs>
<path id="marker" d="M63 127L49 93C44 80 52 69 63 69L64 69C75 69 83 80 78 93L64 127" />
<radialGradient id="shadow">
<stop offset="10%" stop-color="rgba(0,0,0,0.4)" />
<stop offset="90%" stop-color="rgba(0,0,0,0)" />
</radialGradient>
</defs>
</svg>
<!-- Further down the html document -->
<svg viewBox="0 0 128 128" style="width:64px; height:64px" xmlns="http://www.w3.org/2000/svg" version="1.1">
<!-- This use element works fine! -->
<use xlink:href="#marker" style="fill:black" />
<!-- But this fill attribute does not! -->
<rect x="5" y="5" width="20" height="20" fill="url(#shadow)" />
</svg>
Why is it possible to use shapes from other svg elements, but not attribute values like this? When I move the shadow gradient into a defs element inside the visible svg element, the reference works perfectly.
Here is a JSFiddle that illustrates both working and non-working: https://jsfiddle.net/7tfna0L8/2/
The solution
Robert Longson pointed out that my "repository" of reusable svg had a style of display:none. For me, that feels like the correct way to do this. After all, this repository should not be displayed in any way. The problem is that the browser optimizes this by probably not even parsing any style at all, which makes it possible to reference elements, but not style (like my gradient)
Working jsFiddle: https://jsfiddle.net/atornblad/7tfna0L8/3/
Your far-gradient is in an svg which has a style of display:none. That disables all CSS within that fragment so it doesn't work. Try width="0" height="0" instead of display:none.
Related
Is there a way to fix the HTML validation error? While keeping using the SVG as the source code of the <img> tag?
Error: Bad value data:image/svg+xml;utf8,<svg
xmlns='http://www.w3.org/2000/svg' height='10px' width='20px'></svg>
for attribute src on element`
My source code:
<img alt="homepage" src="data:image/svg+xml;utf8,<svg
xmlns='http://www.w3.org/2000/svg' height='10px' width='20px'></svg>"
/>
To use an SVG as a data URI within an <img> element, the SVG code needs to be escaped:
<img alt="homepage" src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='10px' width='20px'%3E%3C/svg%3E">
There are several free tools for doing this, such as URL-encoder for SVG.
If you want a non-interactive svg, use with script fallbacks to png version (for older IE and android < 3). One clean and simple way to do that:
<img src="your.svg" onerror="this.src='your.png'">
your.svg being the path to your svg.
This will behave much like a GIF image, and if your browser supports declarative animations (SMIL) then those will play.
If you want an interactive svg, use either <iframe> or <object>.
If you need to provide older browsers the ability to use an svg plugin, then use <embed>.
For svg in css background-image and similar properties, modernizr is one choice for switching to fallback images, another is depending on multiple backgrounds to do it automatically:
div {
background-image: url(fallback.png);
background-image: url(your.svg), none;
}
An additional good read is this blogpost on svg fallbacks.
For inline SVG; <svg> tags can be inserted as <svg> elements directly into the HTML and not part of the <img> tag. As it is inline SVG the <img> tag is pretty redundant as all the required parameters can be held inside the <SVG>.
Read about it here
Example:
<html>
<head>
<title>SVG Demo</title>
</head>
<body>
<svg
viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice"
style="width:35%; height:35%; position:absolute; top:0; left:0; z-index:-1;">
<linearGradient id="gradient">
<stop class="begin" offset="0%"/>
<stop class="end" offset="100%"/>
</linearGradient>
<rect x="0" y="0" width="100" height="100" style="fill:#cc9966;" />
<circle cx="50" cy="50" r="30" style="fill:#f9f333;" />
</svg>
</body>
</html>
How can I use percentage values for the d attribute of a path tag?
For example:
<path stroke-width="4" d="M1% 10% l100% 0" />
does not work.
Since I want to reuse the elements in svg tag on change in svg size, I'm looking for absolute values (in percentage).
Thanks on advance..
SVG path data only allow dimensionless numbers, period.
If you want to change the size of a path, you will be doing that with transform attributes or by establishing a new viewport. For example, you could wrap your path with a <svg> element inside your outermost <svg>:
<svg ...>
<svg viewBox="0 0 100 100" x="0" y="10%" width="100%" height="100%">
<path stroke-width="4" d="M1 10 l100 0" />
</svg>
</svg>
There, you define the path coordinates as absolute values. The inner <svg> defines a viewBox such that the path spans it to the amount you want. Relative sizing and positioning is then possible with the x, y, width and height attribute.
If you want to reuse the same element multiple times, you can do the same with <symbol> (a template that won't be rendered itself) and <use> elements referencing it:
<svg ...>
<symbol id="myPath" viewBox="0 0 100 100">
<path stroke-width="4" d="M1 10 l100 0" />
</symbol>
<!-- with relative sizes -->
<use xlink:href="#myPath" width="100%" height="100%" />
<!-- with absolute sizes -->
<use xlink:href="#myPath" width="200" height="160" />
<!-- using transforms -->
<use xlink:href="#myPath" transform="translate(50, 0) scale(3.5)" />
</svg>
EDIT: Firefox seems to be the only browser that supports this. I'm
looking for a solution for Chrome.
I'm trying to have a svg header that repeats on multiple pages of a website, and I can achieve that with <use>, but the problem is that a hyperlink in the svg (namely the logo) does not respond to click events.
Here is a simplified snippet that shows the problem. The left box with the inline hyperlink works fine, but when it is included via the <use> tag, it doesn't respond to a click, as can be seen with the right box.
<svg width="300" height="100">
<svg id="link">
<a href="https://google.com">
<rect width="100" height="100" />
</a>
</svg>
<use x="200" xlink:href="#link"></use>
</svg>
It's also available here: https://jsfiddle.net/sh8276gu
Because SVG is XML based and not HTML based, you can't use a normal HTML <a> tag and instead have to include links using Xlink.
This is the same type of linking method you applied within your <use> tag. The reformatted code using Xlink would look like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="300" height="100">
<svg id="link">
<a xlink:href="https://google.com">
<rect width="100" height="100" />
</a>
</svg>
<use x="200" xlink:href="#link"></use>
</svg>
You can read more about including links in SVG here.
So I'm trying to make a simple textpath .svg that would be a vertical line with some text. The problem I am getting is that the <defs> tags seem to throw everything off. I think it has something to do with my xlink:href but I can't seem to pin down what exactly.
<svg version="1.1"
baseProfile="full"
width="20" height="600"
xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="testPath" d="M 10 10 L 10 600 z"
stroke="black" stroke-width="3" />
</defs>
<text>
<textpath xlink:href="#testPath">
teeeest
</textpath>
</text>
</svg>
Any help would be appreciated.
Your sample will work fine inlined in a browser, because the browser knows about the xlink namespace.
If your SVG is an external file, then more strict XML parsing is performed and all namespaces used have to be defined.
All you need to do is add a definition for the xlink namespace to your outermost <svg> element.
<svg version="1.1"
baseProfile="full"
width="20" height="600"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
SVG is a case sensitive language so textpath actually needs to be written as textPath.
If you embed the SVG in html then you don't need namespaces as html doesn't support them (unlike xhtml). If you have your SVG standalone you'll also need xmlns:xlink="http://www.w3.org/1999/xlink" on the root <svg> element.
Chrome seems not to display <use> elements in inline svg. Here is an example (code below or view it at http://www.bobwyttenbach.com/chromeuse.html):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Chrome use-tag bug?</title>
</head>
<body>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="200px" height="200px" viewBox="0 0 200 200">
<defs>
<g id="test1">
<circle cx="100" cy="100" r="50" fill="red"/>
</g>
</defs>
<g>
<rect x="0.5" y="0.5" width="199" height="199" stroke="black" fill="none"/>
<use xlink:href="#test1" x="0" y="0"/>
</g>
</svg>
<p>Above is inline svg with a use tag; below is the same svg linked through an object tag. Below is correct.</p>
<object data="chromeuse.svg" width="200" height="200"></object>
</body>
</html>
The red circle does not appear in the inline svg but does appear when the same svg is linked through an object tag. Safari, Firefox, Opera, and Internet Explorer 9 all display the inline svg correctly.
Am I doing something wrong? Is this a known Chrome bug (I haven't found it listed)? Any workarounds?
Don't know if this question is still relevant, but I've met such a case recently and I pretty sure that somebody else will meet the case (especially those who tries to make use of SVG sprites for the first time).
In my case I've joined 16 SVG icons in one sprite manually into sprite.svg, and in this file I've omitted important meta information:
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
I had no first line at all, and all I had on the second line was an opening <svg> tag with no meta attributes (xmlns and xmlns:xlink). As soon as I brought back all this omitted meta information, my graphics from sprite.svg started to display properly.
Hope it helps someone.
Ok so I deleted my last post as I incorrectly tried to figure out why the use element was working for me and not for you. What I can say is that I am using a modified version of this source, https://code.google.com/p/svg-edit/ , so in short, my answer is to walk through and see how they do it. I believe its demonstrated when you insert an image from their library.
I spent a long time debugging inline svg use elements not showing up. The chrome bug discussed by BobW seems fixed at this time. To eliminate the same issue caused by something else entirely, try commenting out the <base href="somethingsomethingsomething" /> tag from your HTML.
Of course, this will likely break every relative link on your site, but the <use> elements now show up. One step forward, half a step back :)
Related info here:
Using base tag on a page that contains SVG marker elements fails to render marker