Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

svg as background-image: xlink to id in original document

Tags:

html

svg

We have an icon library that we inline to the bottom of the document, like

<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="icon1" viewBox="0 0 100 100">
    <rect x="0" y="0" width="100" height="100" fill="green"/>
  </symbol>
  <symbol id="icon2" viewBox="0 0 100 100">
    <rect x="0" y="0" width="100" height="100" fill="red"/>
  </symbol>
</svg>

Those icons are simply referenced wherever we need them, like

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" width="16px" height="16px">
  <use xlink:href="#icon1"/>
</svg>

Now sometimes we need to use the icons as a background-image, similar to

<div style="width:16px; height:16px; background-size:cover; background-image: url(//placehold.it/16x16)"></div>

It is possible to use svgs as background images using data:image/svg+xml data URIs as described here:

<div style='width:16px; height:16px; background-size:cover; background-image:url(&apos;data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect x="0" y="0" width="100" height="100" fill="red"/></svg>&apos;)'></div>

However, referencing IDs from inside the data URI does not work in the same way:

<h3>referenced in <code>svg</code></h3>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" width="16px" height="16px">
  <use xlink:href="#icon"/>
</svg>

<h3>referenced in <code>background-image</code>
<div style="width:16px; height:16px; background-size:cover; background-image:url(&quot;data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 100 100'><use xlink:href='#icon'/></svg>&quot;)"></div>

<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="icon" viewBox="0 0 100 100">
    <rect x="0" y="0" width="100" height="100" fill="red"/>
  </symbol>
</svg>

I assume the data:image/svg+xml creates a new "context" for the document, so #icon refers to a node inside the data:image/svg+xml (which is not there, because it is in the original document).

Is there a way to reference the original document (like with something similar to ShadowRoot.host from the Shadow DOM API)? (maybe something like xlink:href=":host#icon")

The only workaround that would come to my mind is to use JavaScript to inline the used symbol:

Array.from(document.querySelectorAll('[style*="data:image/svg+xml;utf8,"]'))
  .forEach(function(e) {    
    e.style.backgroundImage = getComputedStyle(e).backgroundImage.replace(
      /<use xlink:href='#([^']+)'\/>/g,
      function(match, id) {
        return document.getElementById(id).innerHTML.replace(/(^\s*|\s*$)/g, '').replace(/"/g, "'")
      }
    )
  })
<h3>referenced in <code>background-image</code> with JS inlining</h3>
<div style="width: 16px; height: 16px; background-size: cover; background-image: url(&quot;data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 100 100'><use xlink:href='#icon'/></svg>&quot;)"></div>
<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="icon" viewBox="0 0 100 100">
    <rect x="0" y="0" width="100" height="100" fill="red"/>
  </symbol>
</svg>

But I would really hope to avoid JavaScript at all.

like image 713
Dominik Schreiber Avatar asked Apr 04 '18 10:04

Dominik Schreiber


Video Answer


1 Answers

This is a subtle variation on a common question.

Is there a way to reference the original document

The answer is no. Any file (and this includes those in the form of a Data URL) loaded as an <img> or background-image etc, need to be self contained. They are loaded as a stand-alone object, and cannot reference other files.

You would need to include the <symbol> in your Data URL.

like image 162
Paul LeBeau Avatar answered Nov 15 '22 03:11

Paul LeBeau