use
to symbol
The use
element has three separate behaviors
depending on what element it is referencing:
a svg
element, a symbol
element or any other graphical element.
In this chapter we would focus on the symbol
element.
What is symbol
?
The SVG 1 definition
of the symbol
was hilariously bare-bone. It basically only acknowledges that such
an element exists and that's it. This is probably the reason why it's so poorly supported.
The SVG 2 definition
of the symbol
is far better but still doesn't really go into nitty-gritty details.
And more importantly, doesn't explain why we need it in the first place.
In simple terms, symbol
is just an invisible, nested svg
.
Why does it even exist then? That's a good question and I have no idea.
Unlike nested svg
, symbol
cannot be rendered directly, even when it is located outside defs
.
And it isn't just display:none
. symbol
and all its content are invisible by design
and can be rendered only via use
.
And since symbol
is just a nested svg
, it also has its own viewport and must be clipped,
which confuses a lot of people.
Let's say we have an SVG like this:
<svg viewBox="0 0 200 200">
<symbol id="symbol1">
<circle cx="0" cy="0" r="80" fill="green"/>
</symbol>
<use xlink:href="#symbol1" transform="translate(100 100)"/>
</svg>
A symbol
with a green circle at 0,0 rendered with a 100,100 offset.
You would probably imagine to see a circle in the center of the image.
Wrong!
Wait, why there is only a quarter of the circle visible? Where the rest have gone?
Well, this is symbol
for you. Remember that just like a nested svg
, symbol must be clipped.
And by default, the clip region is the same as the current viewport, aka our root svg
element.
What a rendered would do is that it would create a new canvas with the same size as the parent one.
So 200x200 in our case. Draw symbol
's content onto it, clipping everything outside the canvas.
Draw symbol
's canvas onto the main canvas using the transform specified on the use
element.
Since out circle starts at 0,0 - our symbol canvas would have only the bottom-right quarter of the circle, which then be moved to the center of the main canvas.
In fact, we can losslessly rewrite our SVG above into:
<svg viewBox="0 0 200 200">
<clipPath id="clipPath1">
<rect x="0" y="0" width="200" height="200" fill="black"/>
</clipPath>
<g clip-path="url(#clipPath1)" transform="translate(100 100)">
<circle cx="0" cy="0" r="80" fill="green"/>
</g>
</svg>
Also, since symbol
is just a nested svg
, it also affected by the
use
to svg
size resolving logic.
Overall, symbol
is quite useless, unintuitive and poorly supported
(Inkscape 1.2 basically ignores it). I would strongly advise against using it.