Chrome 仅在某些网站上强制在框架上使用白色背景

Chrome is forcing a white background on frames only on some websites

我正在构建一个注入本地页面的 Web 扩展,但我遇到了一个奇怪的 Chrome 限制在某些网站上:我无法将 iframe 设置为保持透明:

在 GitHub.com(登录后)或 Google 上试试:

document.body.insertAdjacentHTML(
  'afterbegin',
  '<iframe style="background: red" srcdoc="<style>body {background:none}">'
)

您会看到显示的是 iframed 页面的背景(白色),而不是元素的背景(在本例中为红色以突出显示问题)。

如果您在 Whosebug 或 Twitter 上尝试相同的代码,您会发现 iframe 是红色的。

我认为这是由于安全问题,但奇怪的是,它甚至发生在这个缺乏任何安全措施的简单网站上 header:https://sjmulder.nl/en/textonly.html

Firefox 和 Safari 不受影响。

Element.insertAdjacentHTML()

The insertAdjacentHTML() method of the Element interface parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position. It does not reparse the element it is being used on, and thus it does not corrupt the existing elements inside that element. This avoids the extra step of serialization, making it much faster than direct innerHTML manipulation.

这与chrome如何解析HTML以及它使用的顺序有关。

对于寻求快速 copy-paste 答案的任何人:在注入的 iframe 中包含一个 color-scheme 元 header。它必须匹配网页的 color-scheme header(如果存在)。如果网站没有元数据,请不要添加元数据 header。由于这需要通过编程来确定这样的 header 是否存在内容值是什么,因此省略了这些步骤,但是一旦方案已知,注入代码将如下所示:

document.body.insertAdjacentHTML(
    'afterbegin',
    '<iframe style="background: red" srcdoc="' +
    '<meta name=\'color-scheme\' content=\'light dark\'>' + 
    '<style>body {background:none}">')

下一个更详细的答案,以及我是如何发现它的。

屏幕截图显示 macOS 处于深色模式。如果您转到 OS 设置并在明暗之间切换外观,这应该会在 iframe 后面交替显示白色和红色。试试看是否会发生这种情况。

经过一些实验,我发现如果一个网站有一个元 header 用于 color-scheme:

<meta name="color-scheme" content="light dark">

与 Github.com 和 sjmulder.nl, an iframe without matching header is only able to handle light mode correctly, and renders a white background if user device is set to prefer dark mode. I suspect this is because "major browsers default to light mode if not otherwise configured" 的情况一样。

您可以对此进行试验,并将测试网站上的颜色模式 header 切换为“亮”(仅)和“暗”(仅),而无需在注入的 iframe 中指定任何内容;或者在 iframe 中而不是在网站上定义它,然后切换设备颜色模式首选项以查看效果。我得出的结论是 headers 必须与 iframe 背景颜色匹配才能正确应用。

I reached a strange Chrome limitation on some websites

当一个网站没有定义一个color-scheme meta header并且注入的iframe也没有定义一个时,没有不匹配,也没有问题,这就是为什么只有这个问题出现在一些网站上。我还尝试了其他浏览器(Edge、Opera),它们也有同样的问题,至少在 macOS 上是这样。但它可以通过首先检查页面上是否存在元 header 来在扩展中修复,如果存在,则将相同的 header 应用于注入的 iframe。

按照@neea 所说的,这是真的,我想提出另一个代码修复,因为 color-theme 修复对我没有任何作用。

由于您将 iframe 用于 chrome 扩展,您只需在 iframe 中注入内容脚本,然后获取元标记页面的值,这可以轻松完成document.querySelector('meta[name="color-scheme"]')?.content

我个人在我的项目中使用了react和react-frame-component,在head中插入这个(我也是用的TS):

        <meta
            key="1"
            content={
              (document.querySelector('meta[name="color-scheme"]') as any)
                ?.content ?? 'light'
            }
            name="color-scheme"
          />,

我验证网站是否有那个标签,然后我接受,如果没有,它默认为浅色模式。

这需要注入到您的 iframe HEAD 中。然后它将适用于 google 暗模式或 github.

等网站

阅读@neea 的回答以获得更广泛的解释,但这里有一个适用于任何地方的快速修复:通过样式表或内联将 CSS color-scheme: normal 添加到 iframe:

<iframe style="border: 0; color-scheme: normal" src="your-url.html">

仅当 iframed 页面在深色和白色背景上都能正确显示时才执行此操作。您可能还需要通过元标记在 iframed 页面中设置 color-scheme: normal,但这不是必需的。

为什么 Chrome 这样做

浅色方案通常显示黑色文本和白色背景,深色方案则相反。 Chrome 使用 color-scheme 属性 来了解网站支持的方案。没有它意味着它只支持灯光方案。

如果主页以深色方案显示而 iframed 页面不是,则使用透明背景时,您会在主页的黑色背景上看到 iframed 页面的黑色文本。

这是一种安全机制,可确保 iframed 内容仍然可读。如果删除它,您将需要手动确保 iframed 页面在深色背景下也可读。

现场演示

可以看到深色模式和常规模式下iframe都没有背景

  • 页面只有一种方案,iframe从不显示白底:live link

  • 页面只有2个方案,iframe从不显示白底:live link