135

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?

Marcin
  • 48,559
  • 18
  • 128
  • 201

8 Answers8

183

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>
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • 6
    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. – Marcin Mar 27 '11 at 18:35
  • 30
    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. – Phrogz Mar 27 '11 at 20:16
  • 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. – Marcin Mar 28 '11 at 16:25
  • @Marcin 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`](http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute) and [`viewBox`](http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) attributes? Also, adding `preserveAspectRatio` to the `` 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. – Phrogz Mar 28 '11 at 16:53
  • @Phrogz, viewBox in the referenced file, preserveAspectRatio on the image tag (but not in the referenced file). I'll put up an example soon. – Marcin Mar 28 '11 at 17:31
  • @Phrogz 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. – Ian Storm Taylor Jan 16 '12 at 16:07
  • 9
    @IanStormTaylor An SVG element does not have style properties itself; rather the items inside the SVG element have style. However, when using `` in SVG (or `` or `` 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 ``. – Phrogz Jan 16 '12 at 16:43
  • I'm putting this as a side note: Chrome have the strange behaviour of converting tags to when appending the code via the debugger, and it won't work this way, you have to make your modifications and reload the page. – BiAiB Aug 01 '13 at 14:31
  • What should I do if I have my svg encoded as a string? (and not an external url) – proteneer Feb 02 '15 at 03:54
  • 2
    @proteneer ``. (If you're using JavaScript to set the `href` attribute, you do not need to escape the `<` etc. characters.) – Phrogz Feb 02 '15 at 04:15
  • @Phrogz am I supposed to run my raw string through encodeURIComponent? – proteneer Feb 02 '15 at 04:55
  • Nevermind - I'm using javascript so I don't need to escape it. – proteneer Feb 02 '15 at 04:56
  • I was not able to get anything like this to work beyond two levels. I've posted a separate question about [here](http://stackoverflow.com/q/35903224/559827). – kjo Mar 09 '16 at 22:06
  • Unfortunately, any scripting (JavaScript) inside the child svg is ignored with this method. – AlexG Dec 10 '18 at 14:44
  • 4
    [`xlink:href` is deprecated](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href), now you should just use `href`. Could you update your answer to include that? – Donald Duck Aug 16 '20 at 08:51
  • 1
    The somehow is rasterized...... What if I want to make it run in programs like inkscape.... ? – Xerix Aug 01 '21 at 06:01
  • @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. – Aleksey F. Sep 15 '21 at 05:04
141

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

toshi
  • 2,757
  • 1
  • 16
  • 12
  • 1
    @toshi 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. – Jay Gray Feb 20 '19 at 15:10
  • 1
    +1 for mentioning a self-contained alternative. How does positioning/sizing of such an embedded svg work? – bluenote10 Aug 27 '20 at 21:21
  • I would like to add that you can add transformations to this element: translation, rotation, etc. This way you can dynamically reposition elements – Christoph B Nov 13 '20 at 12:59
  • For instance, to move an element you would write: ... – Christoph B Nov 13 '20 at 13:00
  • Wait, why is it even legal? – polkovnikov.ph May 08 '22 at 02:40
  • Here (https://svgwg.org/svg2-draft/struct.html#SVGElement) in Content model, Structural elements there is ``, but I might misread it. – polkovnikov.ph May 08 '22 at 02:44
  • Note that you may have ids, classes namespace conflicts in that case. – FamousSnake May 22 '23 at 08:37
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!

André Werlang
  • 5,839
  • 1
  • 35
  • 49
dev4life
  • 10,785
  • 6
  • 60
  • 73
  • 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. – Steve Taylor May 15 '20 at 21:13
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" />
Nick Gammon
  • 1,173
  • 10
  • 22
  • @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. – Nick Gammon Apr 10 '20 at 07:48
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).

Saftever
  • 685
  • 6
  • 9
  • 2
    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. – Robert Longson Jun 08 '19 at 12:30
9

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.

Christiaan
  • 838
  • 6
  • 12
3

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

Bigman74066
  • 408
  • 4
  • 12
1

Very Easy

<image x="120" y="720" width="1000" height="900" href="assets/img/image.svg" />