Firefox:如何在不破坏固定位置元素的情况下对整个页面进行灰度化?

Firefox: How to Grayscale an Entire Page without breaking fixed-positioned elements?

为什么 CSS filters,(那些似乎与 size/positioning 无关)破坏了你给后代元素一个固定位置的能力?

除了回答这个问题之外,请提出解决我在下面展示的问题的解决方案。

下面的CSS和HTML只是在视口的中心产生了一个小红框:

#box
{
  background: red; color: white;
  display: inline-block;
  border: solid #333333 10px;
  padding: 5px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Before Filter Corrupts Fixed Positioning</title>
</head>
<body>
<div id ="box">Dead Center<div>
</body>
</html>

现在,假设我们要求整个页面必须以灰度显示。下面唯一有效的变化是添加了 CSS 灰度滤镜。但是,添加此过滤器后,该框将不再遵循我们规定的中心页面定位:

body { filter: grayscale(100%); }
#box
{
  background: red; color: white;
  display: inline-block;
  border: solid #333333 10px;
  padding: 5px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Filter Corrupts Fixed Positioning</title>
</head>
<body>
<div id ="box">Dead Center<div>
</body>
</html>

请注意,该框不再垂直居中。这是一个错误,还是只是 stupid by design?

更新 1:

Temani Afif 在评论中建议在 html 元素(而不是 body 元素)上应用过滤器。虽然这确实解决了 Chrome 中的问题,但在 Firefox 78 中却没有:

html { filter: grayscale(100%); }
#box
{
  background: red; color: white;
  display: inline-block;
  border: solid #333333 10px;
  padding: 5px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Filter Corrupts Fixed Positioning</title>
</head>
<body>
<div id ="box">Dead Center<div>
</body>
</html>

更新二:

根据反馈,我在这里尝试将过滤器应用于 :root,而不是 html。虽然这确实解决了 Chrome 中的问题,但在 Firefox 78 中却没有:

:root { filter: grayscale(100%); }
#box
{
  background: red; color: white;
  display: inline-block;
  border: solid #333333 10px;
  padding: 5px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Filter Corrupts Fixed Positioning</title>
</head>
<body>
<div id ="box">Dead Center<div>
</body>
</html>

我已将此 issue 提交给 Firefox。

总结: 尽管规范允许您将过滤器应用于文档根目录,但为了避免 fixed/absolute-descendants 的封装,我认为通过在与修改大小和位置无关的过滤器上完全避免这种行为,可以改进规范。像灰度这样的过滤器应该对后代的大小或位置的影响为零,因此应用该过滤器的位置(根或非根)无关紧要。在像灰度这样的过滤器上,永远不应该有任何后代的包装。我正在向 W3C here.

解释

更新 3: @NateG 建议将过滤器应用于 body > *。到目前为止,这似乎在 Chromium 和 Firefox 中都有效!见下文:

body > * { filter: grayscale(100%); }
#box
{
  background: red; color: white;
  display: inline-block;
  border: solid #333333 10px;
  padding: 5px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Filter Corrupts Fixed Positioning</title>
</head>
<body>
<div id ="box">Dead Center<div>
</body>
</html>

spec 它说

A value other than none for the filter property results in the creation of a containing block for absolute and fixed positioned descendants unless the element it applies to is a document root element in the current browsing context. The list of functions are applied in the order provided.

所以您的固定元素 ID box 被固定到一个新的 containing block and no longer fixed to the viewport. I also found this much more thorough

在应用某些样式时,您不应该弄乱 body/html,因为由于这些元素的性质,您将面临很多意想不到的结果。

有关在 html 上使用过滤器时您将面临比预期更多问题的相关问题:

您还需要考虑某些属性的传播,例如 and

这是一个使用 position:sticky 模拟固定元素的想法,并考虑使用额外的包装器来避免任何类型的问题:

.html {
  min-height: 100vh;
  filter: grayscale(100%);
}

#box {
  background: red;
  color: white;
  border: solid #333333 10px;
  padding: 5px;
  position: sticky;
  top: 50vh;
  left: 50%;
  transform: translate(-50%, -50%);
  /* the combination of float and transparent shape outside will make the element
     * shrink to fit
     * will not affect the other elements
  */
  float: left;
  shape-outside: linear-gradient(transparent, transparent);
}


/* to simulate content */

.content {
  font-size: 40px;
}

body {
  margin: 0;
}
<div class="html">
  <div id="box">Dead Center
  </div>
  <div class="content">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus volutpat eu ante sed lacinia. In sit amet sapien euismod nibh malesuada convallis pulvinar non mauris. Ut id felis posuere, pharetra justo eget, viverra lacus. Vestibulum tellus libero,
    euismod ac tellus vitae, dapibus mollis tellus. Donec ornare consectetur dui. Vestibulum iaculis neque leo, nec bibendum nisl consectetur in. Curabitur at viverra augue, ac semper neque.
  </div>
</div>

如果将过滤器应用于 body > * 会怎样?性能较低,但可以解决此问题。我承认没有充分考虑它可能引发的新问题,但我想不出它会改变第二个深度元素的包含块的场景。