Ari Seyhun
Ari Seyhun

Reputation: 12531

SVG as background image inlined in style attribute

I'm trying to inline an SVG as a background image of a div. This works fine in a stylesheet:

div {
  background-image:
    url('data:image/svg+xml;charset=utf8,<svg width="30" height="25" viewBox="0 0 30 25" fill="none" xmlns="http://www.w3.org/2000/svg" version="1.1"><path d="M3 14.0204L10.8806 21L27 3" stroke="%231CDFAF" stroke-width="5" stroke-linecap="round"/></svg>');
}

As I'm using a templating language with PHP, I need to make the stroke of the SVG dynamic. To make it dynamic, I'm trying to inline the background image SVG in the HTML style attribute but am unable to escape the " characters in the SVG.

What I've tried:

Inlining with no escaping

<div
  style="background-image: url('data:image/svg+xml;charset=utf8,<svg width="30" height="25" viewBox="0 0 30 25" fill="none" xmlns="http://www.w3.org/2000/svg" version="1.1"><path d="M3 14.0204L10.8806 21L27 3" stroke="%231CDFAF" stroke-width="5" stroke-linecap="round"/></svg>');"
>
</div>

Adding \ before each "

<div
  style="background-image: url('data:image/svg+xml;charset=utf8,<svg width=\"30\" height=\"25\" viewBox=\"0 0 30 25\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"><path d=\"M3 14.0204L10.8806 21L27 3\" stroke=\"%231CDFAF\" stroke-width=\"5\" stroke-linecap=\"round\"/></svg>');"
>
</div>

Replacing " with %22

<div
  style="background-image: url('data:image/svg+xml;charset=utf8,<svg width=%2230%22 height=%2225%22 viewBox=%220 0 30 25%22 fill=%22none%22 xmlns=%22http://www.w3.org/2000/svg%22 version=%221.1%22><path d=%22M3 14.0204L10.8806 21L27 3%22 stroke=%22%231CDFAF%22 stroke-width=%225%22 stroke-linecap=%22round%22/></svg>');"
>
</div>

Is it possible to escape this inlined SVG?

Upvotes: 3

Views: 2165

Answers (2)

Ari Seyhun
Ari Seyhun

Reputation: 12531

For a more complicated SVG, you will need to escape more than just quotes.

The project I was working with is written with the Twig templating language which comes with an escape filter which can be used with html_attr.

For example:

<div
  style="background-image: url('data:image/svg+xml;charset=utf8,{{ '<svg>...</svg>' | escape('html_attr') }}');"
>
</div>

The code for escape('html_attr') can be found here: https://github.com/twigphp/Twig/blob/8a78e8bd20f228469cba345284ef8496f84010dd/src/Extension/CoreExtension.php#L1117

It essentially escapes any character that does not match this regex: [^a-zA-Z0-9,\.\-_]

The main characters necessary to escape are:

"    &quot;
&    &amp;
<    &lt;
>    &gt;

The following JavaScript can be used as a utility to escape an SVG string for use as a HTML attribute:

function escapeHtmlAttr(str) {
  return str.replace(/["&<>]/g, char => {
    switch (char) {
      case '"':
        return '&quot';

      case '&':
        return '&amp';

      case '<':
        return '&lt';

      case '>':
        return '&gt';
    }
    return char;
  });
}

// Usage
const str = `<svg>...</svg>`;           // Your SVG
const escapedStr = escapeHtmlAttr(str); // Escaped SVG

Upvotes: 0

Mr Lister
Mr Lister

Reputation: 46619

Use HTML escapes inside the attribute value: &quot; for a double quote, and (in this case not necessary, but if the need arises) &apos; for a single quote.

<div
  style="background-image: url('data:image/svg+xml;charset=utf8,<svg width=&quot;30&quot; height=&quot;25&quot; viewBox=&quot;0 0 30 25&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot;><path d=&quot;M3 14.0204L10.8806 21L27 3&quot; stroke=&quot;%231CDFAF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;round&quot;/></svg>');"
>
<br style="line-height:25px">
</div>

(Note that I had to give the div some content in order to make the background visible; otherwise its height would have been 0. But that's just for the snippet here.)

Edit: as noted in the comments, the code also works when you use %22 for quotes instead of &quot;.

<div
  style="background-image: url('data:image/svg+xml;charset=utf8,<svg width=%2230%22 height=%2225%22 viewBox=%220 0 30 25%22 fill=%22none%22 xmlns=%22http://www.w3.org/2000/svg%22 version=%221.1%22><path d=%22M3 14.0204L10.8806 21L27 3%22 stroke=%22%231CDFAF%22 stroke-width=%225%22 stroke-linecap=%22round%22/></svg>');"
>
<br style="line-height:25px">
</div>

So could something else have gone wrong in your code? Does your div have a height?

Upvotes: 3

Related Questions