15

I have a simple HTML5 page with an embedded SVG icon element.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
  </head>
  <body>
    <h1>
      <span>ABC</span>
      <svg id="move-icon"
           width="0.7em" height="0.7em"
           viewBox="0 0 10 10"
           style="display: inline-block">
        <defs>
          <marker id="arrow-end-marker"
                  viewBox="0 0 10 10" refX="0" refY="5"
                  markerHeight="3"
                  orient="auto">
            <polygon points="0 0 10 5 0 10" />
   </marker>
        </defs>
        <line x1="5" y1="5" x2="5" y2="7"
              stroke="black" stroke-width="0.03em"
              marker-end="url(#arrow-end-marker)" />
        <line x1="5" y1="5" x2="3" y2="5"
              stroke="black" stroke-width="0.03em"
              marker-end="url(#arrow-end-marker)" />
        <line x1="5" y1="5" x2="5" y2="3"
              stroke="black" stroke-width="0.03em"
              marker-end="url(#arrow-end-marker)" />
        <line x1="5" y1="5" x2="7" y2="5"
              stroke="black" stroke-width="0.03em"
              marker-end="url(#arrow-end-marker)" />
      </svg>
    </h1>
    <p>abc</p>
    <h2>
      <span>DEF</span>
      <!-- reuse here -->&#10067;
    </h2>
    <p>def</p>
  </body>
</html>

Now I want to reuse the embedded SVG icon in the second headline. How can this be done?

ceving
  • 21,900
  • 13
  • 104
  • 178
  • If it is inline then you cannot reference it. So you have to clone it. A better approach would be to use the svg as background graphic. That way you can specify it once in your styles, but that is indeed not inline. – arkascha Dec 11 '15 at 13:48
  • @arkascha I want to add event handlers to the icon. I am not sure, if this will be possible with background images? – ceving Dec 11 '15 at 13:51
  • Not for background element, obviously. Have a try with an `::after` or ::before` pseudo element then. You can use the svg as a background, specify a specific size and attach a js handler to the pseudo element. Or you simply reference the svg as image. Will be loaded only once, since it is cached locally and also allows to attach an event handler. – arkascha Dec 11 '15 at 13:53
  • @arkascha It is not possible to attach event handlers to pseudo elements, because they also no DOM nodes. – ceving Dec 11 '15 at 13:54
  • That is also true again, yep. but can't you place a transparent element in the pseudo element, like a transparent span and attach a handler to that? – arkascha Dec 11 '15 at 13:55

3 Answers3

52

symbol + use + href="#symbol-id"

to define a symbol once, and use it in other svg documents

<!-- define symbol in hidden svg document -->
<svg style="display: none" version="2.0">
  <defs>
    <symbol id="circle-arrow-left" viewbox="0 -10 100 110">
      <path d="m 20 80 A 40 40 0 1 0 20 20"
        fill="none" stroke="#000" stroke-width="10" />
      <path d="M 10 0 v 40 h 40"
        fill="#000" />
    </symbol>
  </defs>
  <!-- to make the circle-arrow-left.svg file
       also usable as image: -->
  <use href="#circle-arrow-left"/>
</svg>

<!-- use symbol of external svg document -->
<button>
  <svg width="50" height="50" version="2.0">
    <use href="#circle-arrow-left" />
  </svg>
</button>

<!-- transform symbol with horizontal flip -->
<button>
  <svg style="transform: scale(-1, 1)" width="50" height="50" version="2.0">
    <use href="#circle-arrow-left" />
  </svg>
</button>

change style: add the new style to where the symbol is used:

<svg style="fill: red"><use href="#s1"/></svg>

<svg class="some-class"><use href="#s2"/></svg>

inkscape does not yet support <svg version="2.0"> with <use href="#some-id"/>.
for svg version 1.1 we need <svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink"> and <use xlink:href="#some-id"/>

related:

https://css-tricks.com/svg-symbol-good-choice-icons/

https://css-tricks.com/svg-use-with-external-reference-take-2/

milahu
  • 2,447
  • 1
  • 18
  • 25
  • 1
    This seems to have been deprecated: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href – timotgl Aug 10 '20 at 16:22
  • 1
    yes, `xlink:href` is deprecated in favor of `href` https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/href – milahu Aug 15 '20 at 11:40
  • This answer says that a separate document is created. I don't see that happening, so it needs an explanation. Is there really a new DOCUMENT node created by this html? – David Spector May 19 '21 at 15:19
  • 1
    "Is there really a new DOCUMENT node created by this html?" - we have one `` document that contains multiple `` documents. each `` document can reference symbols of sibling `` documents. the symbols can be defined before or after the `` – milahu May 22 '21 at 07:18
1

you can save the SVG to a file and use it directly in an < img > tag.like this

<img src="toto.svg" alt="toto description">
aitnasser
  • 1,216
  • 1
  • 9
  • 23
  • I tried it and it seems to me, that I can not define, that the SVG icon should be of the size 0.7em x 0.7em. The img tag allows just pixel units. – ceving Dec 11 '15 at 15:35
  • 2
    if your doing this, your SVG wil be out of the DOM of the page. this means you can't use CSS from the page to alter your SVG content. An embedde SVG can basicly reuse color from parent in dom (but much more if you want) – blobmaster Aug 22 '18 at 08:18
0

I have now a solution, but I have no idea, why this is working. It is possible to define a template, which can be cloned. But cloning means duplicating id attributes. And that means they are not unique any more. But referencing them in the marker-end seems to be still possible. It is a bit strange and I am not sure, if it is wise to follow this track.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
  </head>
  <body>
    <h1>
      <span class="movable">ABC</span>
    </h1>
    <p>abc</p>
    <h2>
      <span class="movable">DEF</span>
    </h2>
    <p>def</p>
    <template id="move-icon">
      <svg width="0.7em" height="0.7em"
           viewBox="0 0 10 10"
           style="display: inline-block; vertical-align: baseline">
        <defs>
          <marker id="arrow-end-marker"
                  viewBox="0 0 10 10" refX="0" refY="5"
                  markerHeight="3"
                  orient="auto">
            <polygon points="0 0 10 5 0 10" />
   </marker>
        </defs>
        <line x1="5" y1="5" x2="5" y2="7"
              stroke="black" stroke-width="0.03em"
              marker-end="url(#arrow-end-marker)" />
        <line x1="5" y1="5" x2="3" y2="5"
              stroke="black" stroke-width="0.03em"
              marker-end="url(#arrow-end-marker)" />
        <line x1="5" y1="5" x2="5" y2="3"
              stroke="black" stroke-width="0.03em"
              marker-end="url(#arrow-end-marker)" />
        <line x1="5" y1="5" x2="7" y2="5"
              stroke="black" stroke-width="0.03em"
              marker-end="url(#arrow-end-marker)" />
      </svg>
    </template>
    <script>
      (function() {
         var icon = document.querySelector('#move-icon');
         var spans = document.querySelectorAll('span.movable');
         for (var i = 0; i < spans.length; i += 1)
           spans[i].parentNode.appendChild (icon.content.cloneNode(true));
       })();
    </script>
  </body>
</html>
ceving
  • 21,900
  • 13
  • 104
  • 178