Search code examples
csssvgshadow-dom

Generate IMG src data URI for SVG with `<use>` elements


Are there security reasons that prevent <use> elements from working in data URI images? I tried something like this:

const svg = document.querySelector("svg");
const img = document.querySelector("img");
img.src = "data:image/svg+xml;charset=UTF-8," + encodeURI(svg.outerHTML);
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <rect id="foo" width="100" height="100"/>
  <use xlink:href="#foo" x="10" y="10"/>
</svg>
<img src=""/>

Both Chrome and Firefox give error messages like this if I access the data URI directly:

enter image description here enter image description here

Example of broken image with <use> element in data URI:

<img src="data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20xmlns:xlink=%22http://www.w3.org/1999/xlink%22%20width=%22110%22%20height=%22110%22%3E%0A%20%20%3Crect%20id=%22foo%22%20width=%22100%22%20height=%22100%22/%3E%0A%20%20%3Cuse%20xlink:href=%22#foo%22%20x=%2210%22%20y=%2210%22/%3E%0A%3C/svg%3E%0A"/>


Solution

  • In modern browsers you don't have to escape < and > in SVG data URI any longer.

    Neither is the outdated xlink notation required.

    But # must be escaped with %23

    And for string handling it is easier to use single quotes

    That makes the correct string:

    data:image/svg+xml,
    <svg xmlns='http://www.w3.org/2000/svg' 
         viewBox='0 0 96 96'>
    <rect id='USED' width='50%' height='50%' stroke='red'/>
    <use href='%23USED' x='24' y='24'/>
    </svg>
    

    <style>
     rect{
      fill:blue !important; /* would work for INline SVG, not for data URI SVG */
     }
     img {
       width:200px;
       filter: drop-shadow(5px 5px 5px gold);
     }
    </style>
    <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' 
              viewBox='0 0 96 96'><rect id='USED' width='50%' height='50%' 
              stroke='red'/><use href='%23USED' x='24' y='24'/></svg>">

    Notes: