且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-09-20 13:45:16

如果将过滤器应用于 body>怎么办? * ?性能较差,但可以解决此问题。我承认没有完全考虑它可能引起的新问题,但是我想不出会改变第二深度元素的包含块的情况。


Why do CSS filters, (ones that seem to have nothing to do with size/positioning) break your ability to give descendant-elements a fixed position?

In addition to answering this question, please suggest a solution that addresses the problem I showcase below.

The CSS and HTML below simply produces a little red box in the center of the viewport:

#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>

Now, let's assume we have a requirement that this whole page must be displayed in grayscale. The only effective change below, is the addition of a CSS grayscale filter. However, upon adding this filter, the box will no longer honor the center page positioning we prescribed:

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>

Notice that the box is no longer centered vertically. Is this a bug, or is it just stupid by design?

Update 1:

Temani Afif recommended, in the comments, applying the filter on the html element (instead of the body element). While this does fix the issue in Chrome, it doesn't in 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>

Update 2:

Based on feedback, here I try applying the filter to :root, instead of html. While this does fix the issue in Chrome, it doesn't in 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>

I submitted this issue to Firefox.

Summary: Even though the spec allows you to apply the filter to the document root, to avoid the encapsulation of fixed/absolute-descendants, I'm of the opinion that the spec could be improved by avoiding this behavior altogether on filters that have nothing to do with modifying size and position. Filters like grayscale should have zero impact on the size or position of descendants and therefore it shouldn't matter where you apply that filter (root or not). On filters like grayscale, there should never be any wrapping of descendants. I am explaining it to the W3C here.

Update 3: @NateG recommended applying the filter to body > *. So far, that seems to work in both Chromium and Firefox! See below:

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>

What if you apply the filter to body > *? Less performant, but may solve this issue. I admit to not fully considering new issues it may raise, but I can't think of a scenario in which it would alter the containing block of second depth elements.