I have an SVG symbol, basically three paths with an all black stroke. This symbol is used heavily across my SVG document using the use tag.
Sometimes i just want to change only one stroke of the instances of the symbol, like color variations, How can i achieve this using SVG+CSS, knowing that I used 'use' to create the symbol instances.
This actually is a very neat trick http://codepen.io/FWeinb/blog/quick-tip-svg-use-style-two-colors, Fabrice Weinberg here is using fill="currentColor" on the symbol so he can change it later using css.
<svg style="display:none;">
<symbol id="test">
<rect x="10" y="10" width="100" height="100" />
<rect x="100" y="10" width="100" height="100" fill="currentColor" />
</symbol>
</svg>
<svg class="icon icon--BlueBlack"><use xlink:href="#test" /></svg>
<svg class="icon icon--BlueGreen"><use xlink:href="#test" /></svg>
and
.icon--BlueBlack{
fill:blue;
}
.icon--BlueGreen{
fill:blue;
color:green;
}
According to the SVG 1.1 spec on the use element:
The effect of a ‘use’ element is as if the contents of the referenced
element were deeply cloned into a separate non-exposed DOM tree […]
The SVG DOM does not show the referenced element's contents as
children of ‘use’ element.
That implies that the referenced elements children are not accessible by traversing your DOM tree. This also holds true for access via css selectors as the spec goes on:
CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree
because its contents are not part of the formal document structure.
It is possible. You can't style the dereferenced symbol contents directly with CSS. But you can style the parent <use> element and have that colour inherit into the symbol. See the answers to the following question for examples.
How to style one particular SVG path in CSS?
Related
I'm trying to inline some images into an SVG that uses xlink:href references pointed to fully qualified local paths. For reasons why see this GitHub issue. The example python does a reasonable job, but it will inline the same image many times in a single SVG which is not optimal.
So I tried a similar approach that converts something like this:
<svg xmlns="http://www.w3.org/2000/svg">
<image x="0" y="-144" width="101px" height="101px" xlink:href="/path/to/file.png" />
<image x="0" y="-144" width="101px" height="101px" xlink:href="/path/to/file.png" />
</svg>
To this
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<image id="file.png_1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA..." />
</defs>
<use x="0" y="+144" width="101px" height="101px" href="#file.png_1" />
<use x="0" y="-144" width="101px" height="101px" href="#file.png_1" />
</svg>
The problem
The way this renders (Safari and Chrome), it seems that width and height have no effect on the <use>.
I can get the desired result to render identically to the original if I move the width and height onto the <defs><image/></defs>. But doing this makes the assumption that no SVG will EVER use the same image twice with different sizes.
Despite reading the SVG 1.1 Standard, I'm still no further forward on understanding how to size a <use> element without explicitly sizing it on the referenced <image> element.
In a comment the OP is asking for an example:
#enxaneta could you show a very short worked example as an answer.
In the next example I'm putting an image in a symbol. The image has a width and a height. Also the symbol has a viewBox. In this case the viewBox of the symbol has the same size as the image.
I'm using the symbol with use.The use element has a x and y attributes for the upper left corner. Also the use has a width and a height. Please observe that I'm preserving the same aspect ratio as the symbol's viewBox.
<svg viewBox="0 0 65 50">
<symbol id="i" viewBox="0 0 22 9.8">
<image width="22" height="9.8" href="https://assets.codepen.io/222579/bone300.svg"/>
</symbol>
<use href="#i" x="10" y="7" width="44" height="19.6" />
</svg>
According to the SVG specification width and height are ignored on a use element unless that use element points to a symbol or an svg element.
The width and height properties on the ‘use’ element override the values for the corresponding properties on a referenced ‘svg’ or ‘symbol’ element when determining the used value for that property on the instance root element.
So wrapping the image in a symbol element and then pointing the use to the symbol should work.
Hello at the moment I'm trying to incorporate SVG as the main display format for my application. However I found a rather strange behavior when it comes to the visibility attribute. Given this example:
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg">
<g id="visibility-test">
<rect x="100" y="0" height="140" width="40"/>
<rect x="0" y="100" height="40" width="140" visibility="visible"/>
</g>
</svg>
This behaves as expected. The two rectangles are visible. Now I want to make the whole group I set the visibility of the g-element to hidden like such:
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg">
<g id="visibility-test" visibility="hidden">
<rect x="100" y="0" height="140" width="40"/>
<rect x="0" y="100" height="40" width="140" visibility="visible"/>
</g>
</svg>
If you look at this in the browser it hides one rectangle (the one without any attribute) but the one with the visibility attribute is still visible. I would've expected a behavior where the visibility of the whole branch is affected but the parent element.
Is there any way to achieve this behavior without toggling the visibility of ever child?
SVG does not work like HTML in the DOM. SVG is namespaced. The browser uses a HTML parser to parse the HTML in the webpage. And the browser will also use the XML parser for the SVG markup on the webpage. So they are treated differently, even though they are rendered on the same page.
If the parent has the visibility attribute. And any of their children also has a visibiity attribute. Then you need to change that childs visibility attribute to inherit. SVG will allow a child to still be visible even if its parent is set to hidden.
W3C SVG visibility attribute spec:
http://www.w3.org/TR/SVG11/painting.html#VisibilityProperty
Available values for the SVG visibility attribute:
visible | hidden | collapse | inherit
But you should either place the visibility attribute on the parent <g> element, or place it individually. The default value for the SVG attribute is inherit. So SVG will honor the visibility state of the element it is applied to regardless of its parent visibility state.
I'm trying to define my iconset-svg using a symbol tag instead of a g tag but it isn't working as the icon isn't rendered. If I define some icon using it works.
The code:
<iron-iconset-svg name="br-icons">
<svg style="display: none">
<defs>
<symbol id="icon-menu" viewBox="0 0 1024 1024">
<title>menu</title>
<path class="path1" d="M64 192h896v192h-896zM64 448h896v192h-896zM64 704h896v192h-896z"></path>
</symbol>
</defs>
</svg>
</iron-iconset-svg>
I am using it like this:
<iron-icon icon="br-icons:icon-menu"></iron-icon>
Does anyone know how I can get this working?
The response I got from the Polymer team was "you need to use a <use> element with a <symbol>, which doesn't let you style it". So I think for now you'll want to stick with <g>. Apologies if I'm mistaken here, I am not an SVG expert by any means :)
In my markup, I have a chunk like this:
<svg width="0" height="0" style="display:none" id="dummy-wedge">
<g class="dummy" transform="translate(100, 100)">
<defs>
<clipPath id="clip1">
<polygon id="clip1Shape" points="-100,-100 0,-100 0,0 -100,-20" />
</clipPath>
</defs>
<circle id="" cx="0" cy="0" r="52" fill-opacity="0"
stroke="#ffffff" stroke-opacity="0.6" stroke-width="50"
pointer-events="visiblePainted" clip-path="url(#clip1)" />
</g>
</svg>
What I'm wanting to do is grab that chunk and clone it into a different svg root element to create a bunch of wedges, each with a different position and clip segment. That part is cool, but the frustration is that each cloned clipPath element will need to receive a new ID which will then have to be inserted into the clip-path attribute of the matching element.
I know that if all the arcs were the same length, I could have a common clip and use rotate transforms, but they aren't necessarily the same length.
Is it possible to declare a clip polygon using a topological relationship rather than by explicitly naming it? Alternatively, is there a better way to define an arc like this outside of using paths?
Thanks.
Why do you need to use clipping? Couldn't you just use path elements with the various arc segments in them?
There's no declarative way (yet) to get the behaviour you are after, but this is what the SVG Parameters specification is meant to address. Look at the examples there and the script implementation provided for processing the content (as a way to support the current browsers). NOTE: it's still a working draft, and is subject to change.
I'm having a play with SVG and am having a few problems with positioning. I have a series of shapes which are contained in the g group tag. I was hoping to use it like a container, so I could set its x position and then all the elements in that group would also move. But that doesn't seem to be possible.
How do most people go about positioning a group of elements which you wish to move in tandem?
Is there any concept of relative positioning? e.g. relative to its parent
Everything in the g element is positioned relative to the current transform matrix.
To move the content, just put the transformation in the g element:
<g transform="translate(20,2.5) rotate(10)">
<rect x="0" y="0" width="60" height="10"/>
</g>
Links: Example from the SVG 1.1 spec
There is a shorter alternative to the previous answer. SVG Elements can also be grouped by nesting svg elements:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<svg x="10">
<rect x="10" y="10" height="100" width="100" style="stroke:#ff0000;fill: #0000ff"/>
</svg>
<svg x="200">
<rect x="10" y="10" height="100" width="100" style="stroke:#009900;fill: #00cc00"/>
</svg>
</svg>
The two rectangles are identical (apart from the colors), but the parent svg elements have different x values.
See http://tutorials.jenkov.com/svg/svg-element.html.
As mentioned in the other comment, the transform attribute on the g element is what you want. Use transform="translate(x,y)" to move the g around and things within the g will move in relation to the g.
There are two ways to group multiple SVG shapes and position the group:
The first to use <g> with transform attribute as Aaron wrote. But you can't just use a x attribute on the <g> element.
The other way is to use nested <svg> element.
<svg id="parent">
<svg id="group1" x="10">
<!-- some shapes -->
</svg>
</svg>
In this way, the #group1 svg is nested in #parent, and the x=10 is relative to the parent svg. However, you can't use transform attribute on <svg> element, which is quite the contrary of <g> element.
I know this is old but neither an <svg> group tag nor a <g> fixed the issue I was facing. I needed to adjust the y position of a <g> tag which also had animation on it.
The solution was to use both the <svg> and <g> tag together:
<svg y="1190" x="235">
<g class="light-1">
<path />
</g>
</svg>