svg / svgo

⚙️ Node.js tool for optimizing SVG files
https://svgo.dev/
MIT License
20.88k stars 1.39k forks source link

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

Open rnwst opened 1 year ago

rnwst commented 1 year ago

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>
  2. 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:

rnwst commented 1 year ago

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.

johnkenny54 commented 1 month ago

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>.

GreLI commented 1 month ago

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.