嵌套在iframe中的SVG出现不一致问题

5
我需要在iframe内部渲染一些SVG,并且需要使用srcdoc属性来实现。但由于某种原因,我所做的方式会导致SVG的某些属性无法正确显示。
如下截图所示,iframe中的代码是相同的。 screenshot 以下是重现此问题的代码:
<svg height="150" width="300">
  <defs>
    <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
      <stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
    </linearGradient>
  </defs>
  <ellipse cx="100" cy="70" rx="85" ry="55" fill="url(#grad1)" />
</svg>

<br><br>

<iframe width="300" height="150" srcdoc='<svg height="150" width="300">
  <defs>
    <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
      <stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
    </linearGradient>
  </defs>
  <ellipse cx="100" cy="70" rx="85" ry="55" fill="url(#grad1)" />
</svg>'></iframe>

看起来与linearGradients有关,或者与URL以及它们在这种情况下的行为有关。

我最近遇到了一些有关iframes和srcdocs的问题,并在SO上发布了这个问题,得到了很好的回答:iframes rendering mysteriously differently from regular web pages? 这对许多不一致性有所帮助,但似乎与这个问题无关。

我正在使用Chrome/Webkit。


好的,我已经确认了,在嵌套和父文档中的渐变之间并没有ID冲突,并且#字符也不会像在数据URI中一样破坏解析(回退颜色可以正常呈现)。 - AmeliaBR
1个回答

12

这似乎是 iframe srcdoc 文档如何解析内部目标链接的不幸结果。

使用 srcdoc 创建的文档应该被赋予特殊的基础 URL about:srcdoc

然而,在该文档内,用于解析外部链接或样式表的基础 URL 是父文档的 URL。这可能意味着 ID 应该在父 DOM 中解析而不是本地 DOM 中解析。但很明显这并没有发生,因为在您原始的示例中,父文档中有一个具有该 ID 的有效渐变。现在,这可能是由于跨域限制阻止了来自单独文档的资源,但我在控制台上没有相应的错误。

当您开始使用目标片段进行其他操作时,情况变得非常混乱(且跨浏览器不一致)。

在这个 jsFiddle 中,我使用目标片段来

  • 从两个文档中引用渐变(一个用于描边,一个用于填充),但在Chrome(v38)和Firefox(v33)中都不能正常显示(IE根本不支持srcdoc)。

  • 重复使用两个文档中的元素;在FF中,<use>都无法呈现,Chrome呈现了本地椭圆形重复使用,这表明在此情况下,它按照本地文档解析片段。

  • 定义超链接的目标。在这种情况下,FF会给我POST错误,但Chrome成功导航到父文档中的目标(请注意,:target样式会应用)。当然,这仅在父文档具有可导航的URL时才有效(即保存的JS Fiddle,但不是堆栈片段)。

总之,规范中存在歧义,实现中也存在不一致性,建议寻找替代方案,例如使用数据URI作为iframe的src。请注意,这仍然无法在不支持iframe数据URI的IE中工作,并且您需要对文档中的任何#%字符进行URL编码。

iframe srcdoc和URL片段测试用例

ellipse:target {
    stroke:red;
}
<svg height="150" width="300">
  <defs>
    <linearGradient id="grad1" >
      <stop offset="0" style="stop-color:rgb(255,255,0);stop-opacity:1" />
      <stop offset="1" style="stop-color:rgb(255,0,0);stop-opacity:1" />
    </linearGradient>
  </defs>
  <ellipse id="parentEllipse" cx="100" cy="70" rx="85" ry="55" fill="url(#grad1)" />
</svg>

<br><br>

<iframe width="300" height="150" srcdoc='<svg height="150" width="300">
  <defs>
    <linearGradient id="grad2" >
      <stop offset="0" style="stop-color:rgb(255,255,0);stop-opacity:1" />
      <stop offset="1" style="stop-color:rgb(255,0,0);stop-opacity:1" />
    </linearGradient>
  </defs>
<a xlink:href="#parentEllipse">
  <ellipse id="ellipse" cx="100" cy="70" rx="85" ry="55" fill="url(#grad1) blue"  stroke="url(#grad2) green" stroke-width="10px" /></a>
  <use xlink:href="#ellipse" y="50"/>
  <use xlink:href="#parentEllipse" x="50" />
</svg>'></iframe>


我不知道为什么这个答案没有得到赞同,这是我发现的关于这个主题最好的解决方案。是否可以以任何其他内联方式指定模式,而无需引用URL? - KalEl
2
这是一个解决方案,至少在Chrome中有效:在选择器ID之前添加about:srcdoc。 - KalEl
也适用于Firefox。感谢@KalEl!虽然还是有些混乱,但至少有了解决方法。 - AmeliaBR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接