Why is this an empty space appearing inside of SVG element? - html

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.

Related

Why the <use> element in SVG doesn't work?

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).

Multiple perspectives into a single SVG

Is it possible to have a multiple different views into single SVG, or even just simulate that sort of effect with some clever use of groups? I wish to show different parts of a potentially very large SVG, but I'd rather avoid rendering it multiple times. Is there some sort of simple way of doing this?
for standalone SVGs there is the <view/> element which you can use to show only portions of your graphics. try this in a standalone file.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" width="100" height="100">
<view id="circleView" viewBox="0 0 100 100"/>
<view id="rectView" viewBox="100 0 100 100"/>
<a xlink:href="#rectView">
<circle cx="50" cy="50" r="45" fill="blue"/>
</a>
<a xlink:href="#rectView">
<rect x="105" y="5" width="90" height="90" fill="royalblue" stroke="#53c"></rect>
</a>
</svg>
just click on the cirlce to see the rect and on the rect to see the circle.
this also works if you reference your svg via <img>
<img src="your.svg#circleView"/>
<img src="your.svg#rectView"/>
i found this to be not working for inlined SVG. Here you can use a similar aproach. You can just change the viewBox of your SVG. In contrast to the above, viewBoxes can even be animated!
<svg viewBox="0 0 460 360" width="200" height="200">
<polygon id="triangle" points="100,10,450,350,10,350" fill="#52c" />
<circle id="circle" cx="50" cy="50" r="45" fill="#c52" />
<rect id="rect" x="255" y="155" width="200" height="200" fill="#5c2" />
<animate attributeName="viewBox" to="250 150 210 210" dur="0.5s" begin="circle.click" fill="freeze" />
<animate attributeName="viewBox" to="0 0 100 100" dur="0.5s" begin="triangle.click" fill="freeze" />
<animate attributeName="viewBox" to="0 0 460 360" dur="0.5s" begin="rect.click" fill="freeze" />
</svg>
<br/>click on any of he shapes!
of course you can also just set the viewBox by script...
if you want to reference different parts of your SVG, you might use the <use> - Element as suggested in the other answers.
It's pretty simple to do. You just use the <use> element as Robert suggests. Here is a working example.
svg {
border: solid 1px black;
}
svg#original {
width: 450px;
}
<svg viewBox="0 0 450 300" id="original">
<circle cx="225" cy="150" r="150" fill="orange"/>
<circle cx="175" cy="110" r="25" fill="black"/>
<circle cx="275" cy="110" r="25" fill="black"/>
<circle cx="225" cy="70" r="150" fill="none" stroke="black" stroke-width="20" stroke-dasharray="0 145 180 1000"/>
</svg>
<br/>
<!-- part of the original at the same scale -->
<svg width="150" height="150">
<use xlink:href="#original" x="-50" y="0" width="450" height="300"/>
</svg>
<!-- part of the original at 0.5x scale -->
<svg width="150" height="150">
<use xlink:href="#original" x="0" y="0" width="450" height="300" transform="scale(0.5)"/>
</svg>
<!-- part of the original at 3x scale (and using a different method to achieve the scaling) -->
<svg width="150" height="150">
<use xlink:href="#original" x="-450" y="-255" width="1350" height="900"/>
</svg>

How do I use SVG icons in HTML?

I have an svg file with 3 icons.
When I import it via the <img> tag, I get the 3 icons one below each other.
I want to use the icons in a row, one next to the other.
How can I use them separately?
The .svg file:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16.3px"
height="26.9px" viewBox="0 0 16.3 26.9" enable-background="new 0 0 16.3 26.9" xml:space="preserve">
<g id="bg">
</g>
<g id="ui">
<g>
<polygon points="8.1,0 10.3,4.3 15.2,5 11.7,8.3 12.5,13 8.1,10.8 3.8,13 4.6,8.3 1.1,5 6,4.3 "/>
<polygon fill="none" stroke="#000000" stroke-miterlimit="10" points="8.1,13 10.3,17.3 15.2,18 11.7,21.3 12.5,26 8.1,23.8
3.8,26 4.6,21.3 1.1,18 6,17.3 "/>
</g>
</g>
<g id="pop_ups">
</g>
</svg>
Thanks!
Use the SVG file as a sprite.
Create an icon-sized element, hiding the overflow:
.icon {
display: inline-block;
width: 16.3px;
height: 13.45px;
overflow: hidden;
}
Position the SVG within the element so the icon shows through:
.icon > img {
position: relative;
}
.darkStar > img {
top: 0;
}
.lightStar > img {
top: -13.45px;
}
Demo (using inline SVG instead of a linked <img>, which defeats the purpose, but is easier to demo here):
.icon {
display: inline-block;
width: 16.3px;
height: 13.45px;
overflow: hidden;
}
.icon > svg {
position: relative;
}
.darkStar > svg {
top: 0;
}
.lightStar > svg {
top: -13.45px;
}
<span class="icon lightStar">
<svg width="16.3px" height="26.9px">
<polygon points="8.1,0 10.3,4.3 15.2,5 11.7,8.3 12.5,13 8.1,10.8 3.8,13 4.6,8.3 1.1,5 6,4.3" />
<polygon points="8.1,13 10.3,17.3 15.2,18 11.7,21.3 12.5,26 8.1,23.8 3.8,26 4.6,21.3 1.1,18 6,17.3" fill="none" stroke="#000000" stroke-miterlimit="10" />
</svg>
</span>
<span class="icon darkStar">
<svg width="16.3px" height="26.9px">
<polygon points="8.1,0 10.3,4.3 15.2,5 11.7,8.3 12.5,13 8.1,10.8 3.8,13 4.6,8.3 1.1,5 6,4.3" />
<polygon points="8.1,13 10.3,17.3 15.2,18 11.7,21.3 12.5,26 8.1,23.8 3.8,26 4.6,21.3 1.1,18 6,17.3" fill="none" stroke="#000000" stroke-miterlimit="10" />
</svg>
</span>
You can use fragment identifiers to display only part of the SVG file in any particular img element.
The advantage of this approach is that the "individual sprites" in your SVG file are defined in your SVG file, so when using it elsewhere you don't need to know anything of the internal structure, you can just ask for what you want by name:
<button>
<img src="x.svg#star1" alt="*">
</button>
The most cross-platform-compatible solution is add some SVG views which define which part of the image to show for which ID fragment. The view syntax is similar to the global viewBox attribute of the root SVG element*:
<view id="star1" viewBox="0 0 10 10"/>
Here's a good blog post (with a live example) which explains the technique in great detail.
*note that I haven't calculated that viewBox value for your SVG, you'll have to figure it out yourself.
I'm not sure if you mean vertically or horizontally, but here's something I found from Codepen.io which has a lot of SVG samples you might want to go through.
http://codepen.io/jonnowitts/pen/waONVV
Here he has SVG's lined up vertically in a row.
<button type="button" id="positive">
<div class="content">
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="42" viewBox="-9 0 38 40" preserveAspectRatio="xMidYMid meet">
<path class="check" fill="none" d="M0 20 L8 28 L25 10" stroke="white" stroke-width="3"/>
</svg>
<span>Positive</span>
</div>
</button>
<button id="negative">
<div class="content">
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="42" viewBox="-9 0 38 40" preserveAspectRatio="xMidYMid meet">
<path class="cross-1" fill="none" d="M0 10 L20 30" stroke="white" stroke-width="3"/>
<path class="cross-2" fill="none" d="M20 10 L0 30" stroke="white" stroke-width="3"/>
</svg>
<span>Negative</span>
</div>
</button>
<button id="warning">
<div class="content">
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="42" viewBox="-3 0 38 40" preserveAspectRatio="xMidYMid meet">
<polygon class="triangle"
stroke="white"
stroke-width="2"
fill="none"
points="15,4 0,34 30,34"
/>
<path class="exclaim-1" d="M15 14 L15 22 Z" stroke-width="4" stroke="white" fill="none" />
<path class="exclaim-2" d="M15 24 L15 29 Z" stroke-width="4" stroke="white" fill="none" />
</svg>
<span>Warning</span>
</div>
</button>

Make css background image (svg) responsive

I want to use a SVG file as background image (css).
Here is my SVG:
<?xml version="1.0"?>
<svg width="428" height="100" xmlns="http://www.w3.org/2000/svg">
<!-- Created with Method Draw - http://github.com/duopixel/Method-Draw/ -->
<g>
<title>background</title>
<rect fill="none" id="canvas_background" height="102" width="430" y="-1" x="-1"/>
<g display="none" overflow="visible" y="0" x="0" height="100%" width="100%" id="canvasGrid">
<rect fill="url(#gridpattern)" stroke-width="0" y="1" x="1" height="400" width="580"/>
</g>
</g>
<g>
<title>Layer 1</title>
<text stroke="#000" transform="matrix(1.22606 0 0 1.22606 -24.7533 -46.6879)" opacity="0.3" font-style="italic" xml:space="preserve" text-anchor="left" font-family="Helvetica, Arial, sans-serif" font-size="24" id="svg_1" y="87.150366" x="22.228393" stroke-width="0" fill="#000000">Hello world!</text>
</g>
</svg>
I encoded it with http://b64.io and used it like this:
#new-hello-world {
background-image: url(…);
background-repeat: no-repeat;
}
Now my problem is that the SVG is not responsive. How can I solve this?
Any help would be greatly appreciated.
EDIT:
I already tried to make the svg width and height 100% but that did not work.
Give the <svg> element a viewBox attribute e.g. viewBox = "0 0 428 100" although chipChocolate.py's suggestion of viewBox="0 0 580 400" might work better depending on exactly what you want to see.

How to center a circle in an svg

I'm lost as to how I can put a circle element at the center of an svg without it moving around or getting bigger and smaller as I resize the page.
I've tried viewBox but it doesn't do what I expected.
An alternative to the viewBox variant:
<svg width="100" height="100">
<circle cx="50%" cy="50%" r="10"/>
</svg>
The circle would however get bigger if you zoom the whole page.
Another way is to use a zero-length path with rounded linecaps, like this:
<svg viewBox="0 0 100 100">
<path d="M50 50" stroke-linecap="round" stroke="black"
fill="none" vector-effects="non-scaling-stroke"
stroke-width="20"/>
</svg>
http://jsfiddle.net/dAEB9/
<svg viewBox="-1 -1 2 2"> <!-- viewBox defines the coordinate system.-->
<circle cx="0" cy="0" r="1" />
</svg>
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
http://jsfiddle.net/QrNnN/
Put your circle in group <g> and use transform="translate(x, y)".
<svg viewBox="0 0 400 400">
<g transform="translate(200, 200)">
<circle cx="0" cy="0" r="200" style="" fill="darkOrange"></circle>
</g>
</svg>
Result:
Simple example on JSFiddle:
https://jsfiddle.net/mattez/0p2pstrf/