因为 filter 置灰网站引发的线上事故!

452 阅读2分钟

最近在做一个置灰网站的需求,我跟大部分网站一样使用了 CSS 的 filter 滤镜功能,但是事情并没有原本的那么简单,如果使用不当,还会引发线上事故。

位置问题

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    html,body {
      width: 100%;
      height: 100%;
    }
    * {
      margin: 0;
      padding: 0;
    }
    .container {
      /* filter: grayscale(1); */
      padding-top: 50px;
    }
    .box {
      position: fixed;
      left: 0;
      bottom: 0;
      width: 100%;
      height: 300px;
      background: pink;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>hello</h1>
    <div class="box"></div>
  </div>
</body>
</html<img src=">" alt="" width="30%" />

页面效果:红元素是相对于页面底部定位,设置了置灰样式,元素相对于父级定位了。

左边是正常网站,右边是置灰的网站,就因为加了一行CSS代码,导致我的样式错乱,严重影响页面的正常使用。

原因是:配置了 css filter 属性的元素,其子元素的 fixed 定位会失效。

为什么会这样?最后我在 MDN 上找到这样一段话:

  • fixed
  • 元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transformperspective 或 filter 属性非 none 时,容器由视口改为该祖先。

由于我上面的代码中,给类名为 container 元素加了 filter 属性,所以 box 元素的定位从视口改为了 container 元素。

【解决方案】

web 端: 将 filter 设置在 html 上即可。 小程序:需逐个元素排查,确保设置了 filter 的元素,不包含存在 fixed 定位的子元素。

层叠问题

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    html,body {
      width: 100%;
      height: 100%;
    }
    * {
      margin: 0;
      padding: 0;
    }
    
    .box {
      position: fixed;
      left: 0;
      top: 0;
      width: 100%;
      height: 300px;
      background: pink;
    }
    .hello {
      filter: grayscale(1);
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="box"></div>
    <h1 class="hello">hello</h1>
  </div>
</body>
</html>

页面效果:红元素相对于页面顶部定位,设置了置灰样式,定位元素无法覆盖没定位的元素。

预计的效果是定位的元素会覆盖下面类名为的 hello 的元素,但是由于我的 hello 元素使用了 CSS 的 filter 属性导致无法被定位的元素覆盖了。

原因是:配置了 css filter 属性的元素,z-index 会被提升,可能会覆盖掉其他有定位元素

所以上面代码中类名为 box 和 hello 的元素处于同一个层级中,所以后面的元素覆盖了前面的,要想不被覆盖,可以给定位的元素加上 z-index 值来解决。或者修改一下元素的先后顺序,把 box 放在 hello 的后面。

【解决方案】

注意调整 z-index 层级。

本文正在参加「金石计划 . 瓜分6万现金大奖」