Home > Software design >  Can an encoded SVG for background-image be imported from a separate file?
Can an encoded SVG for background-image be imported from a separate file?

Time:03-12

I have an SVG file:

myIcon.svg

<svg>.....</svg>

I want to use it in my css:

   .body {
       background-image: url(../myIcon.svg);
   }

since an svg needs to be encoded for it to work as a background-image, that leaves me with something like this:

.body {
    background-image: url("data:image/svg xml,***<here place encoded svg>***");
}

Is there a way to store the encoded svg in it's own file for maintainability? Since it's not in html tags, I'm not sure how save it to it's own file or if it's even possible.

CodePudding user response:

Put some hours in investigating which characters are not allowed in a data:image/svg URI
Many encoders convert < and >, but those are valid.

  • Load your external SVG file and replace all invalid characters

  • Create a new <style> element with the background-image

Wrapped in a modern Web Component so it totally does not matter when the script is executed

⚠️ xmlns="http://www.w3.org/2000/svg" must be present in the SVG file; it is not required when you inline SVGs in modern browsers.

<svg-import-background src="//svg-cdn.github.io/red.svg" selector="#container"></svg-import-background>
<svg-import-background src="//svg-cdn.github.io/yellow.svg" selector="div > h2"></svg-import-background>
<svg-import-background src="//svg-cdn.github.io/blue.svg" selector="pre"></svg-import-background>

<style>
  body { font:16px Arial; color:beige }   h2   { color: black }
</style>

<div id="container">
  <h2>Web Component &lt;svg-import-background&gt;</h2>
  Inject external SVG file into CSS background-image
  <pre>
&lt;svg-import-background ATTRIBUTES:
                                   src="PATH TO SVG FILE"
                                   selector="Element selector"
  </pre>
</div>

<script>
  customElements.define("svg-import-background", class extends HTMLElement {
    async connectedCallback() {
      let svg = await (await fetch(this.getAttribute("src"))).text();
      svg = svg.replace(/\>[\t\s\n ] \</g, "><"); // replace all BETWEEN tags
      svg = svg.replace(/#/g, "#");
      svg = svg.replace(/"/g, "'");
      this.innerHTML = `<style>${this.getAttribute("selector") || "body"}{` 
        `background-image:url("data:image/svg xml;charset=UTF-8,${svg}")` 
      `}</style>`;
    }
  })
</script>

<svg viewBox="0 0 8 8"><rect width="100%" height="100%" fill="gold"></rect></svg>

Re: encodeURIComponent

Yes, you can replace all 3 replace statements with:

svg = encodeURIComponent(svg);

The difference is what is injected in your HTML code.

The 3 replace statements injects:

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><rect width='100%' height='100%' fill='#f00'></rect></svg>

encodeURIComponent injects:

It is up to you which one you want to debug

  • Related