带有 foreignObject 的 SVG 在用作图像 src 属性时具有不同的高度

SVG with foreignObject has a different height when used as an image src attribute

提问人:MigMit 提问时间:5/4/2023 更新时间:11/2/2023 访问量:83

问:

我正在尝试拍摄现有元素的图像。首先,我将图像复制到 SVG 元素中的 foreignObject,然后序列化它并将其用作“数据”图像源。但是由于某种原因,在 Chrome 中,我看到元素的呈现方式略有不同。有谁知道为什么会这样,可以做些什么来纠正它?

我的 HTML 是这样的:

<!DOCTYPE html>
<html>

<head>
  <style>
    html,
    body {
      margin: 0
    }

    .x {
      border: 1px solid black;
      float: left;
      width: 100.3px;
    }

  </style>
  <script>
    function test() {
      let x = document.getElementById('xx')
      let i = document.getElementById('if')
      i.contentDocument.body.appendChild(document.getElementById('sv').cloneNode(true))
      let c = i.contentDocument
      let s = c.getElementById('sv')
      let t = c.getElementById('st')
      let f = c.getElementById('fo')
      i.width = x.offsetWidth * 2
      i.height = x.offsetHeight
      s.viewBox.baseVal.width = x.offsetWidth
      s.viewBox.baseVal.height = x.offsetHeight
      s.width.baseVal.value = x.offsetWidth
      s.height.baseVal.value = x.offsetHeight
      f.width.baseVal.value = x.offsetWidth
      f.height.baseVal.value = x.offsetHeight
      t.textContent = document.getElementsByTagName('STYLE')[0].textContent
      f.appendChild(x.cloneNode(true))
      d = new XMLSerializer().serializeToString(s)
      g = c.createElement('IMG')
      g.width = x.offsetWidth
      g.height = x.offsetHeight
      g.src = 'data:image/svg+xml,' + encodeURIComponent(d)
      c.body.appendChild(g)
    }
  </script>
</head>

<body onclick="test()">
  <div class="x" id="xx">
    <ul>
      <li>a</li>
      <li>b</li>
      <li>c</li>
      <li>d</li>
      <li>e</li>
    </ul>
  </div>
  <svg xmlns="http://www.w3.org/2000/svg" id="sv" viewBox="0 0 100 100" width="100px" height="100px">
    <style id="st"></style>
    <foreignObject id="fo" width="100px" height="100px" style="background:lightgray"></foreignObject>
  </svg>
  <iframe id="if"></iframe>
</body>

</html>

这是结果(单击正文中的某处后):1

左边的列表是原始列表,然后是我用于 SVG 的蓝图,然后是包含两个元素的 iframe:一个是 SVG 元素,里面有一个 foreignObject,显示相同的列表,另一个是 IMG 元素,它具有完全相同的 SVG,序列化,作为其源代码。出于某种原因,它们在 Chrome 中的渲染略有不同(在 Firefox 中很好)。

JavaScript SVG 外对象

评论

0赞 MigMit 5/4/2023
@RobertLongson做到了:bugs.chromium.org/p/chromium/issues/detail?id=1442475——但我想知道是否有一些解决方法,或者我只是遗漏了一些东西。

答:

0赞 MigMit 5/5/2023 #1

好吧,所以,似乎确实有一个解决方法。它在 Safari 中使事情陷入混乱,因此,我没有一个很好的跨平台代码,但问题是 HTML 的呈现方式略有不同,具体取决于 .对于图像,它始终为 1。但对于主要内容,它是 2(视网膜显示)。window.devicePixelRatio

解决方法是首先将 SVG 中的内容复制为此处的内容,但将该 SVG 包装在 DIV 中;然后根据克隆内容的实际 和 调整所有维度,然后才进行 XML 序列化和其余部分。zoom = 1/devicePixelRatiooffsetHeightoffsetWidth