svgo icon indicating copy to clipboard operation
svgo copied to clipboard

SVGO creates invalid self-closing tags inside `<foreignObject>` elements

Open rnwst opened this issue 2 years ago • 3 comments

Describe the bug When an empty tag is present inside of a <foreignObject> element, SVGO converts it to a self-closing tag. This results in tags that are invalid HTML and are misinterpreted by the browser.

To Reproduce Steps to reproduce the behavior:

  1. Run svgo test.svg --pretty --indent=2, where test.svg:
<svg xmlns="http://www.w3.org/2000/svg" width="100px" height="100px" viewBox="0 0 10 10">
  <foreignObject x="0" y="0" width="10" height="10" style="font-size:2px">
    <p style="margin-top:0">
      <span style="height:4px;display:inline-block"></span>
      Some text.
    </p>
  </foreignObject>
</svg>
  1. Observe the result, which is:
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 10 10">
  <foreignObject width="10" height="10" x="0" y="0" style="font-size:2px">
    <p style="margin-top:0">
      <span style="height:4px;display:inline-block"/>
      Some text.
    </p>
  </foreignObject>
</svg>

Note that the empty <span> element has been converted to a self-closing tag. This results in invalid HTML, since <span> is not a void element. The browser actually interprets the self-closing tag as an opening tag, and then automatically closes the tag later on. This is essentially equivalent to:

<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 10 10">
  <foreignObject width="10" height="10" x="0" y="0" style="font-size:2px">
    <p style="margin-top:0">
      <span style="height:4px;display:inline-block">
      Some text.
      </span>
    </p>
  </foreignObject>
</svg>

(See here for more information.) When viewing the SVG in a browser, keep in mind that <foreignObject> elements will not be rendered unless the SVG is inside of an HTML page. To fix this, add <html> tags and save the file as an HTML file.

Expected behavior Inside <foreignObject> elements, empty elements should not be converted to self-closing tags.

Version info:

  • SVGO Version: 3.0.2
  • NodeJs Version: v19.2.0
  • OS: Linux

rnwst avatar Dec 18 '22 14:12 rnwst

Turns out this is a duplicate of #1473. That issue also points out that SVGO treats whitespace inside <foreignObject> elements incorrectly, something I hadn't noticed initially, but is still an issue in version 3.0.2.

rnwst avatar Dec 18 '22 14:12 rnwst

I don't think the self-closing tag is invalid. The content within a <foreignObject> has to be XML, which means it's XHTML, not HTML, so <span/> should be equivalent to <span></span>.

There is still a problem with whitespace being trimmed, and as pointed out in #1678, the safest solution is to preserve all white space within a <foreignObject>.

johnkenny54 avatar Aug 20 '24 02:08 johnkenny54

Yep, <foreignObject> is a different world, which SVGO knows nothing about. That's not a bug, since special handling of <foreignObject> was never implemented (as far as I concerned). PRs are welcome.

GreLI avatar Aug 20 '24 10:08 GreLI