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('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>')'></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("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>")"></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("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>")"></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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With