最近在做一个置灰网站的需求,我跟大部分网站一样使用了 CSS 的 filter 滤镜功能,但是事情并没有原本的那么简单,如果使用不当,还会引发线上事故。
位置问题
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.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>
页面效果:红元素是相对于页面底部定位,设置了置灰样式,元素相对于父级定位了。
左边是正常网站,右边是置灰的网站,就因为加了一行CSS代码,导致我的样式错乱,严重影响页面的正常使用。
原因是:配置了 css filter 属性的元素,其子元素的 fixed 定位会失效。
为什么会这样?最后我在 MDN 上找到这样一段话:
•
fixed
•元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed
属性会创建新的层叠上下文。当元素祖先的transform
,perspective
或filter
属性非none
时,容器由视口改为该祖先。
由于我上面的代码中,给类名为 container 元素加了 filter 属性,所以 box 元素的定位从视口改为了 container 元素。
【解决方案】
web 端:将 filter 设置在 html 上即可。小程序:需逐个元素排查,确保设置了 filter 的元素,不包含存在 fixed 定位的子元素。
层叠问题
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.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 层级。