【问题标题】:CSS filter:invert not working with background-colorCSS过滤器:反转不适用于背景色
【发布时间】:2020-07-29 11:16:04
【问题描述】:

我将以下 CSS 应用于 <html> 标签:filter: invert(1);

即使background-color 的元素,所有元素都会反转,(Chrome v80)

一旦我在 Safari iOS 13 / Safari MacOS 上尝试相同的操作,除了 的 background-color

之外,每个元素都会反转

我正在运行的所有浏览器都支持 CSS 过滤器属性:

https://caniuse.com/#feat=mdn-css_properties_filter

有人能解释一下这种行为吗?

html {
  filter: invert(1);
  /* this background-color does not change on ios+other browsers */
  background: #fff;
  padding: 50px;
}

body {
  background-color: #0000ff;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.text {
  text-align: center;
  color: red;
}
<div class="text">
  If it works: color should not be red, background should not be blue
</div>

【问题讨论】:

  • 尝试添加html{background:#fff}
  • @TemaniAfif 我已经更新了 sn-p,同样的问题没有倒过来。
  • 很有趣,same discrepancy happens with opacity + background-color,FF 不会让不透明度影响 html 的背景,而 Chrome 在 iframe 中不会影响,但在页面在自己的窗口中运行时默认为白色。并且 Safari 具有 Chrome 的逆行为(这似乎更符合 IMM 逻辑)。 @TemaniAfif 知道规范对此有什么看法吗?
  • 为什么不用:root这个用js切换背景呢?如果我没记错的话,这通常就是现在创建黑暗主题等的方式。
  • 是的。但我正在考虑应用实际的颜色反转应用

标签: html css sass


【解决方案1】:

TL;DR:不要过多地使用 html 元素。

简单的解决方法是阻止body 的背景传播到文档的画布,但通过删除其边距并应用您在html 上的所有样式,使其大小与html 相同身体,以及你在body 上的那些到包装器&lt;div&gt;

html {
  /* block body's background propagation */
  background: #FFF;
}


/* move all one layer down */
body {
  filter: invert(1);
  background: #fff;
  padding: 50px;
  /* make it cover the full canvas */
  margin: 0;
}
.wrapper {
  background-color: #0000ff;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.text {
  text-align: center;
  color: red;
}
<div class="wrapper">
  <div class="text">
    If it works: color should not be red, background should not be blue and border should not be white
  </div>
</div>

更深入的观察:

这里有几个概念在起作用,它们之间的交互并不是那么容易掌握(至少对我来说......)。

  • “渲染层”:绘制页面时,通常会有多个渲染层,可能嵌套在其中应用过滤器或不透明度等效果。规范仅定义“堆叠上下文”,对于我们这里的情况,它们是相同的。
  • "Document's canvas":每个文档都有一个背景画布,它不存在于 DOM 中,它是最深的“渲染层”。
  • "Background propagation":一些特殊元素的 CSS background 属性具有特殊行为。值得注意的是,htmlbody 可以为“文档的画布”提供自己的背景。基本工作流程是

    • 如果html 的背景不是none 而不是transparent,则将其用于“文档画布”。
    • 否则,如果body 的背景不是none 而不是transparent,则将其用于“文档画布”。
    • 其他任何你想做的事情(通常浏览器呈现白色纯色)。
  • “后处理”效果如 filteropacity 应该在其所有内部内容都已渲染后应用于整个“渲染层”。

  • 在元素上设置此类“后处理”效果应该隔离该元素并从中创建一个新的“渲染层”。

现在,“文档的画布”应该如何受到这些“后处理”效果的影响还不清楚,而且我在规范中找不到任何明确的答案。

可以肯定的是,我们存在 [Compat] 问题...

不仅并非所有浏览器都遵循相同的规则,而且当页面作为独立窗口或 iframe 呈现时,某些浏览器的行为也会有所不同。

由于测试结果在窗口渲染和框架渲染之间确实存在差异,并且 StackSnippet 只允许框架渲染,我不得不将测试用例外包给 this plnkr

html {
  background: red;
  height: 50vh;
  border: 10px solid green;
}

.opacity {
  opacity: 0.5;
}

.filter {
  filter: invert(1);
}

body {
  background: yellow;
  margin: 10vh;
  border: 2px solid green;
}

这些针对主流浏览器的测试结果如下:

窗口化时:(屏幕截图顺序,从左到右:nothingfilteropacity、过滤器+不透明度)。

  • Firefox 不会对文档的画布应用过滤器或不透明度。
  • Edge 不会对文档的画布应用滤镜或不透明度。 (与 Firefox 相同)
  • Chrome
  • Chrome >= 81 对文档的画布应用过滤器和不透明度。
  • Safari 可以
    • 在没有设置不透明度时统一应用滤镜。
    • 不在文档的画布上应用不透明度
    • 在设置不透明度时为&lt;html&gt; 创建一个新图层,并在&lt;html&gt; 的背景上应用不透明度和过滤器。
      然而,它现在使用&lt;body&gt; 的背景颜色作为文档的画布......但让它不受过滤器的影响。

加框时:(截图顺序,从左到右:nothingfilteropacity、过滤器+不透明度)。

  • Firefox 不会对文档的画布应用过滤器或不透明度。
  • Edge 不会对文档的画布应用滤镜或不透明度。 (与 Firefox 相同)
  • Chrome(所有版本)不会对文档的画布应用过滤器或不透明度。
  • Safari 可以
    • 在没有设置不透明度时统一应用滤镜。
    • 在设置不透明度时将文档的画布设置为透明,并为 &lt;html&gt; 创建一个应用不透明度的新图层。
    • 在设置不透明度时为&lt;html&gt; 创建一个新图层,并在&lt;html&gt; 的背景上应用不透明度和过滤器。
      但是它现在将文档的画布设置为透明。

再说一次,我不知道这里的结果是否符合规范,我知道作为网络作者,我们应该尽可能避免弄乱它。


后记:

  • 这是引入新 Chrome 行为的 Chromium issue
  • a proposal 允许网络作者将文档的画布背景定义为对某些设备透明。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2021-05-19
    相关资源
    最近更新 更多