CSS过滤器:反转不适用于背景色

Posted

技术标签:

【中文标题】CSS过滤器:反转不适用于背景色【英文标题】:CSS filter:invert not working with background-color 【发布时间】: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>

【问题讨论】:

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

【讨论】:

以上是关于CSS过滤器:反转不适用于背景色的主要内容,如果未能解决你的问题,请参考以下文章

使用CSS3滤镜让图片反转颜色

过滤器:模糊(1px);不适用于 Firefox、Internet Explorer 和 Opera

如何使用 SVG 过滤器将白色图像反转为黑色?

避免 css 过滤器反转 div::selection 中的更改

悬停在链接上时如何反转整个页面的颜色

WPF GridControl单元格值与过滤值相同时,改变单元格背景色