Embed SVG in SVG?
Asked Answered
S

8

142

I have an SVG document, and I would like to include an external svg image within it, i.e. something like:

<object data="logo.svgz" width="100" height="100" x="200" y="400"/>

("object" is just an example - the outer document will be SVG rather than xhtml).

Any ideas? Is this even possible? Or is the best thing for me to simply slap the logo.svg xml into my outer SVG document?

Sciatic answered 27/3, 2011 at 17:59 Comment(0)
C
190

Use the image element and reference your SVG file. For fun, save the following as recursion.svg:

<svg width="100%" height="100%" viewBox="-100 -100 200 200" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
  <circle cx="-50" cy="-50" r="30" style="fill:red" />
  <image x="10" y="20" width="80" height="80" href="recursion.svg" />
</svg>
Celina answered 27/3, 2011 at 18:14 Comment(17)
Thanks, for some reason my googling for this just did not work until after I posted this question. I note that width and height must be present for the image to render.Sciatic
One interesting observation: the latest versions of Firefox, Chrome, and Safari all show only one level of recursion (two dots) using the above. However, if you save the above as "a.svg" and change the image to "b.svg", and then also save it as "b.svg" with the image referencing "a.svg", then Firefox will show additional levels of recursion for each time you reload the alternating files. It appears to cache result each time you load the file, going one level deeper.Celina
I should add that unfortunately FireFox and WebKit seem to handle the image tag inconsistently, with FF's behaviour seeming to be erroneous (weird placement of the image, odd scaling). My solution was to just paste the SVG in, in the end.Sciatic
@Sciatic That surprises me greatly. Do you have a simple test case that produces different results in Chrome versus FF? Does the referenced SVG file have both preserveAspectRatio and viewBox attributes? Also, adding preserveAspectRatio to the <image /> element might help. Though I'm glad you have a working solution I'd be interested in further investigating and squashing problems you have with proper referencing.Celina
@Phrogz, viewBox in the referenced file, preserveAspectRatio on the image tag (but not in the referenced file). I'll put up an example soon.Sciatic
@Celina Do you know if it is possible to then style the linked SVG file as if it were an SVG shape? I can't seem to get it to work.Hulton
@IanStormTaylor An SVG element does not have style properties itself; rather the items inside the SVG element have style. However, when using <image> in SVG (or <img> or <embed> in HTML) to reference an SVG file you are not given access to the underlying DOM. As such, no, you cannot style elements inside an SVG element that has been referenced by an <image>.Celina
I'm putting this as a side note: Chrome have the strange behaviour of converting <image> tags to <img> when appending the code via the debugger, and it won't work this way, you have to make your modifications and reload the page.Variolous
What should I do if I have my svg encoded as a string? (and not an external url)Fibroma
@Fibroma <image xlink:href="data:image/svg+xml;utf8,&lt;svg …&gt;… &lt;/svg&gt;" />. (If you're using JavaScript to set the href attribute, you do not need to escape the < etc. characters.)Celina
@Celina am I supposed to run my raw string through encodeURIComponent?Fibroma
Nevermind - I'm using javascript so I don't need to escape it.Fibroma
I was not able to get anything like this to work beyond two levels. I've posted a separate question about here.Uhlan
Unfortunately, any scripting (JavaScript) inside the child svg is ignored with this method.Inlier
xlink:href is deprecated, now you should just use href. Could you update your answer to include that?Pica
The <image> somehow is rasterized...... What if I want to make it run in programs like inkscape.... ?Phyfe
@Xerix, the use of image in inkscape produces the same rasterized result and leads to losing vectorness of embedded svg. It can be easily discovered via saving to PostScript with inkscape: the referenced svg is rendered into a raster image (blob) rather than PostScript painting commands on the elements of the referenced svg.Peri
A
146

Or you can actually embed child svg in parent svg like this:

<svg>
    <g>
        <svg>
            ...
        </svg>
    </g>
</svg>

demo:
http://hitokun-s.github.io/old/demo/path-between-two-svg.html

Actinouranium answered 18/12, 2014 at 12:4 Comment(7)
@Actinouranium do you have another example of your answer? i am trying but failing to implement your advice. my 'outer' SVG sets a circle and gradients. my inner SVG is an object. stand-alone, the inner SVG works as expected. but the inner SVG does not display in my implementation of your advice. hence, my request to see another example.Poston
+1 for mentioning a self-contained alternative. How does positioning/sizing of such an embedded svg work?Philpott
I would like to add that you can add transformations to this <g> element: translation, rotation, etc. This way you can dynamically reposition elementsStraightjacket
For instance, to move an element you would write: <g transform="translate(30,10)">...</g>Straightjacket
Wait, why is it even legal?Isosteric
Here (svgwg.org/svg2-draft/struct.html#SVGElement) in Content model, Structural elements there is <svg>, but I might misread it.Isosteric
Note that you may have ids, classes namespace conflicts in that case.Pettway
F
54

It is worth mentioning that when you embed SVGs into another SVG with:

<image x="10" y="20" width="80" height="80" xlink:href="image.svg" />

then the embedded SVG takes a rectangular shape with given dimensions.

That is to say, if your embedded SVG is a circle or some shape other than a square, then it becomes a square with transparency. Therefore, mouse events get trapped into that embeded square and do not reach the parent SVG. Watch out for that.

A better approach is using a pattern. To fill a shape, either a circle, a square or even a path.

<defs>
 <pattern id="pat" x="0" y="0" width="500" height="500" patternUnits="userSpaceOnUse">
   <image x="0" y="0" width="500" height="500" xlink:href="images/mysvg.svg"></image>
 </pattern>
</defs>

Then use the pattern like this:

<circle cx="0" cy="0" r="250" fill="url(#pat)"></circle>

Now your mouse events do not get stuck into transparent image squares!

Furcula answered 10/8, 2014 at 16:28 Comment(1)
That fill pattern is perfect, thank you. For smaller inserts or smaller viewboxes, coders may want to reduce all width and height in equal measure.Shevlo
R
12

I found that using the <image> tag gave a low-quality render of the embedded file. However the following technique worked (to embed an SVG file inside an SVG file - not necessarily for rendering on an HTML page):

  • Edit the SVG file in a text editor.

  • Find the end of the metadata:

    </metadata>
      <g
       id="layer1"
       inkscape:groupmode="layer"
       inkscape:label="Layer 1">
    
  • Insert this line after that group tag:

    <use xlink:href="OTHERFILE.svg#layer1" y="0" x="0" />
    
  • In this case we are including OTHERFILE.svg into the file, and all of layer1 (the first and default layer).

  • Save this and then open the file in Inkscape.

This technique is useful for having a standard background or logo on every page. By putting it first in the file it will be rendered first (and thus at the bottom). You could also lock it by adding this attribute:

sodipodi:insensitive="true" 

In other words:

<use xlink:href="OTHERFILE.svg#layer1" sodipodi:insensitive="true" y="0" x="0" />
Rodin answered 15/5, 2018 at 2:7 Comment(1)
@WilliamEntriken What do you mean by "external files"? The method I described uses an external file, namely the file with the other stuff in it.Rodin
I
11

Note xlink:href has been deprecated, just use href instead, e.g.

<svg viewBox="0 0 512 512">
  <image width="512" height="512" href="external.svg"/>
</svg>

viewBox, width and height values (in this answer) are simply for illustration purpose, adjust the layout accordingly (read more).

Since <image> shares similar spec as <img>, meaning it doesn't support SVG styling, as mentioned in Christiaan's answer. For example, if I have the following css line that set the svg shape color to be the same as the font color,

svg {
  fill: currentColor;
}

The above style wouldn't apply if <image> is used. For that, you need to use <use>, as shown in Nick's answer.

Note id="layer1" and href="OTHERFILE.svg#layer1" values in his answer are mandatory.

Meaning you have to add the id attribute to the external svg file, so you need to host the (modified) external svg file by yourself (your website) or somewhere else. The resulting external svg file looks like this (notice where I put the id):

<svg id="logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  <path d="..."/>
</svg>

The value of id can be anything, I use "logo" in this example.

To embed that svg,

<svg viewBox="0 0 512 512">
  <use href="edited-external.svg#logo"/>
</svg>

If you use the above svg as inline in your html, you don't need xmlns attribute (at least what I know from svgo).

Infirmity answered 8/6, 2019 at 9:32 Comment(1)
viewBox is not mandatory, if you omit it you'll get a different layout, in some cases that might be what you want though. Safari has only just started to support href.Doehne
A
10

I needed to embed a SVG in my SVG but also change its color and apply transforms.

Only Firefox supports the "transform" attribute on the nested svg elements. Changing the color of <image> is also not possible. So a combination of both was needed.

What I ended up doing was the following

<svg>
  <image x="0" y="0" xlink:href="data:image/svg+xml;base64,[base64 of nested svg]"></image>
</svg>

This works on at least Firefox, Chrome and Inkscape.

This behaves the same as the child svg in the parent svg answer with the exception that you can now apply transforms on it.

Asphodel answered 6/1, 2017 at 14:47 Comment(0)
D
3

How about using the SVG <use> tag to embed the extra SVG?

Deutero answered 6/2, 2021 at 14:40 Comment(1)
Can you share an example?Musk
J
3

Very Easy

<image x="120" y="720" width="1000" height="900" href="assets/img/image.svg" />
Juxon answered 2/7, 2021 at 16:53 Comment(1)
Same answer as https://mcmap.net/q/138424/-embed-svg-in-svgExtrauterine

© 2022 - 2024 — McMap. All rights reserved.