Based on https://css-tricks.com/svg-symbol-good-choice-icons/
I have a representation of symbols taken from svg files. The original svgs have properties like x, y, height and width.
When adding the svgs to one svg file and making them symbols, I found that adding x, y height and width attributes to <symbol> is not valid svg.
I resolved the issue for height and width, by adding them in the style attribute of the <symbol> since that one is supported. My question is, how can I go about adding the x and y attributes to the <symbol>?
The final file, is composed of only one <svg> and multiple svg <symbol>
Example original file:
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
Sorry, your browser does not support inline SVG.
</svg>
File after changing it to symbol:
<svg style="display:none;">
<symbol id="circle" width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
Sorry, your browser does not support inline SVG.
</symbol>
</svg>
In the above width and height are not valid attributes for symbol.
The symbol is used the following way:
<svg>
<use xlink:href="#circle" />
</svg>
However, in the above, it doesn't expand to take the width and the height. I also tried nesting an svg inside the symbol like this and it also doesn't respect the height and width:
<svg style="display:none;">
<symbol id="circle">
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
Sorry, your browser does not support inline SVG.
</svg>
</symbol>
</svg>
The <symbol> element does not have x, y, width or height attributes.
Your original file:
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
Sorry, your browser does not support inline SVG.
</svg>
should be converted to:
<svg style="display:none;">
<symbol id="circle">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</symbol>
</svg>
And then reference it with a <use> as follows. If the original SVG had width and height values, then they should go in the <use>.
<svg>
<use xlink:href="#circle" width="200" height="100"/>
</svg>
If you want to position the symbol, use x and y attributes, or a transform on the <use>.
<svg>
<use xlink:href="#circle" width="200" height="100" x="300" y="50"/>
</svg>
<svg>
<use xlink:href="#circle" width="200" height="100" transform="translate(300,50)"/>
</svg>
Note that <symbol> elements do support viewBox, so if your original SVG has a viewBox, it should be added to the symbol.
Related
I'm trying to make the entire SVG image background opaque.
All I could find on my search was how to make specific elements inside the image opaque, but I couldn't find anything regarding the background.
I know how to make the circle itself opaque/transparent, but not the background.
What do I need to add to make everything behind the circle opaque?
This is how the picture looks, note the white/grey squares indicating transparency
<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="100px" viewBox="0 0 300 100">
<circle cx="50" cy="50" r="40" fill="blue"/>
</svg>
Try this out
You can also refer this link for the same: https://www.geeksforgeeks.org/how-to-set-the-svg-background-color/
<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="100px" viewBox="0 0 300 100">
<rect width="100%" height="100%" fill="green" />
<circle cx="50" cy="50" r="40" fill="blue"/>
</svg>
I have the fiddle with this problem. If I set viewBox property on the symbol element, icon displayed correctly. But if I set viewBox with same value on svg element with use inside, around use element appears weird empty space, inside of SVG-container.
Viewport of first variant is the same with viewport of second variant - 35x35px size at 2.5x3.5px coords.
What's the reason of this behavior? Bug or my own mistake?
EDIT: Add picture with correct and incorrect areas.
#svg-icons {
display: none;
}
.icon {
display: inline-block;
border: 1px solid red;
}
.icon + .icon {
margin-left: 20px;
}
<svg version="1.1" id="svg-icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol id="icon-1" viewBox="2.5 3.5 35 35">
<rect x="2.5" y="3.5" stroke="#000000" stroke-miterlimit="10" width="35" height="35" />
<circle fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" cx="20" cy="21" r="14" />
</symbol>
<symbol id="icon-2">
<rect x="2.5" y="3.5" stroke="#000000" stroke-miterlimit="10" width="35" height="35" />
<circle fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" cx="20" cy="21" r="14" />
</symbol>
</svg>
<svg class="icon icon-1" width="100" height="100">
<use xlink:href="#icon-1"></use>
</svg>
<svg class="icon icon-2" viewBox="2.5 3.5 35 35" width="100">
<use xlink:href="#icon-2"></use>
</svg>
This probrem will be solved by thinking about how the use element is treated on drawing.
According to SVG 1.1 2nd edition, use element refers symbol element is treated as svg element on drawing. So the result by that svg structure is same as this.
<svg class="icon icon-2" viewBox="2.5 3.5 35 35" width="100">
<g>
<svg width="100%" height="100%">
<rect x="2.5" y="3.5" stroke="#000000" stroke-miterlimit="10" width="35" height="35" />
<circle fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" cx="20" cy="21" r="14" />
</svg>
</g>
</svg>
Inner svg element has range of 100% width and height positioned at (0,0), and outer svg element has viewBox offset to (2.5, 3.5).
Thus shapes are cutoff by displacement of 2 svg element's rendering ranges.
I have the following simple example. It is stored in image.svg:
<svg>
<defs>
<g id="shape">
<circle cx="100" cy="100" r="100" />
</g>
</defs>
</svg>
However, putting this code in a HTML file doesn't load anything. Why is that?
<svg>
<use xlink:href="#shape" x="10" y="10" />
</svg>
What am I doing wrong? I can't seem to make it work.
If you are using elements from another document, you have to specify the document!
<use xlink:href="#shape" x="10" y="10" />
This means "use the #shape element from the current document".
To import from another document, you need to put the reference to the SVG file in the xlink:href attribute:
<use xlink:href="image.svg#shape" x="10" y="10" />
Obviously you need to check the path is correct here. Note that this is not supported in any version of Internet Explorer, though polyfills are available.
For external svg files you need the namespace ... and I have added a fill to render the circle otherwise it will be transparent:
<svg xmlns="http://www.w3.org/2000/svg" >
<symbol id="shape" width="200" height="200" viewbox="0 0 200 200">
<circle cx="100" cy="100" r="100" fill="currentColor" />
</symbol>
<text y="20">Symbol above will not render unless referenced by use element</text>
</svg>
Then when you reference it you need to use the correct namespace for xlink:
svg.defs-only {
display:block; position: absolute;
height:0; width:0; margin: 0; padding: 0;
border: none; overflow: hidden;
}
svg {
color: orange;
stroke: red;
}
.purple {
color: purple;
stroke: black;
}
<svg class="defs-only" xmlns="http://www.w3.org/2000/svg" >
<symbol id="shape" width="50" height="50" viewbox="0 0 50 50">
<circle cx="25" cy="25" r="20" fill="currentColor" stroke="inherit" />
</symbol>
</svg>
<svg xmlns:xlink="http://www.w3.org/1999/xlink">
<use xlink:href="#shape" x="10" y="10" />
<use xlink:href="#shape" x="80" y="10" class="purple" />
</svg>
If you are referencing an external file, you need to put the filename before the # e.g. image.svg#shape making sure you get the path correct of course.
Note, not all browsers support fragment identifiers - notably IE and Edge - you need to use a javascript polyfill like svg4everybody for those browsers.
Workaround - use svg inline only
You need to have the use-tag inside the SVG with the shape you want to use:
<svg>
<defs>
<g id="shape">
<circle cx="100" cy="100" r="100" />
</g>
</defs>
<use xlink:href="#shape" x="10" y="10" />
</svg>
SVG 2 (when implemented in browsers) will allow to reference another SVG file without any fragment identifier:
New in SVG 2: An href without a fragment allows an entire SVG document to be referenced without having to ensure that it has an ID on its root element.
Before (SVG 1.1):
<!-- my-vector.svg -->
<svg id="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<circle r="10" cx="12" cy="12" />
</svg>
<use href="my-vector.svg#icon"></use>
After (there will be no need to define id="..." on the svg):
<!-- my-vector.svg -->
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<circle r="10" cx="12" cy="12" />
</svg>
<use href="my-vector.svg"></use>
SVG 2 seems to be in the process of development in major browsers (see this Chrome feature and specifically this Chromium issue: Issue 366545: [SVG2] Allow to reference entire files).
When implementing an SVG sprite, an <svg> element is created and svg elements are referenced via the <use> element. The containing <svg> element is then hidden using style="display: none;"
The clip-Path attribute does not render, but the path does. This leaves my path looking different from how I want it to.
How do I use an svg <use xlink:href="#"/> referencing an element with clip-path?
I used grunt-svg-store to create my svg sprite, but have simplified this example for Q&A format https://css-tricks.com/svg-sprites-use-better-icon-fonts/
<svg id="svg-test" style="display: none;">
<clipPath id="my-clip-1">
<circle id="circle-1" cx="50" cy="50" r="50" />
</clipPath>
<path id="svg-test-reference" clip-path="url(#my-clip-1)" d="M10-39.288h80v80H10z" />
</svg>
<!-- Reference SVG <path> by ID with Use -->
<svg class="svg-item" viewBox="0 0 100 100">
<use xlink:href="#svg-test-reference" />
</svg>
Live example on Codepen.io
Use <svg style="width:0; height:0;"> instead of <svg style="display: none;"> to hide the sprite.
<!-- SVG element -->
<svg id="svg-test" style="width:0; height:0;">
<clipPath id="my-clip-1">
<circle id="circle-1" cx="50" cy="50" r="50" />
</clipPath>
<path id="svg-test-reference" clip-path="url(#my-clip-1)" d="M10-39.288h80v80H10z" />
</svg>
<!-- Reference SVG <path> by ID with Use -->
<svg class="svg-item" viewBox="0 0 100 100">
<use xlink:href="#svg-test-reference" />
</svg>
Live example on Codepen.io
In my case, using only "width" and "height" equals to zero, left a void area where should be the image. However, using display:content; instead display:none; works fine, no void area and no image.
I have a page like this , here I have two circles one with yellow color and one with red color , when placed simultaneously , the mouse events are not triggering means the underlying circle mouse event is hidden
<!DOCTYPE html>
<html>
<body>
<h1>My first SVG</h1>
<svg width="100" height="100" style="position:fixed;top:50;left:40;z-index:2;">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" onmouseout="evt.target.setAttribute('opacity','1');" onmouseover="evt.target.setAttribute('opacity','0.5');" onclick="alert('yellow clicked')"/>
Sorry, your browser does not support inline SVG.
</svg>
<svg width="100" height="100" style="position:fixed;top:50;left:40;z-index:1;">
<circle cx="50" cy="50" r="20" stroke="green" stroke-width="4" fill="brown" onmouseout="evt.target.setAttribute('opacity','1');" onmouseover="evt.target.setAttribute('opacity','0.5');" onclick="alert('red clicked')"/>
Sorry, your browser does not support inline SVG.
</svg>
</body>
</html>
The svg elements have an attribute pointer-events, that controls whether an event is fired relating to that element. e.g. If you set pointer-events="none" on your top circle, it becomes transparent, so the event can occur at the bottom circle
<svg id="mySVG" width="400" height="400">
<circle onclick=alert() id=bottomCircle cx=200 cy=200 r=150 fill=red />
<circle pointer-events="none" id=topCircle cx=200 cy=200 r=130 fill=blue />
</svg>
It worked now
<!DOCTYPE html>
<html>
<body>
<h1>My first SVG</h1>
<svg>
<svg width="100" height="100" style="position:fixed;top:50;left:40;z-index:2;">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" onmouseout="evt.target.setAttribute('opacity','1');" onmouseover="evt.target.setAttribute('opacity','0.5');" onclick="alert('yellow clicked')"/>
Sorry, your browser does not support inline SVG.
</svg>
<svg width="100" height="100" style="position:fixed;top:50;left:40;z-index:1;">
<circle cx="50" cy="50" r="20" stroke="green" stroke-width="4" fill="brown" onmouseout="evt.target.setAttribute('opacity','1');" onmouseover="evt.target.setAttribute('opacity','0.5');" onclick="alert('red clicked')"/>
Sorry, your browser does not support inline SVG.
</svg>
</svg>
</body>
</html>