Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

深入探讨 filter 与 backdrop-filter 的异同 #147

Open
chokcoco opened this issue Nov 3, 2021 · 9 comments
Open

深入探讨 filter 与 backdrop-filter 的异同 #147

chokcoco opened this issue Nov 3, 2021 · 9 comments

Comments

@chokcoco
Copy link
Owner

chokcoco commented Nov 3, 2021

本文将深入探讨在 CSS 中两个非常类似的属性 -- filterbackdrop-filter。它们都能完成某些滤镜功能,但是它们肯定也存在差异。那么,为什么在 CSS 中有了 filter 还诞生了 backdrop-filter 了?

带着这个疑问,开始今天的正文。

filter VS backdrop-filter

在 CSS 中,有两个和滤镜相关的属性 -- filterbackdrop-filter

backdrop-filter 是更为新的规范推出的新属性,可以点击查看 Filter Effects Module Level 2。

  • filter:该属性将模糊或颜色偏移等图形效果应用于元素。
  • backdrop-filter: 该属性可以让你为一个元素后面区域添加图形效果(如模糊或颜色偏移)。 它适用于元素背后的所有元素,为了看到效果,必须使元素或其背景至少部分透明。

注意两者之间的差异,filter 是作用于元素本身,而 backdrop-filter 是作用于元素背后的区域所覆盖的所有元素。

它们所支持的滤镜种类:

filter backdrop-filter 备注
url 获取指向SVG过滤器的URI
blur 高斯模糊滤镜
brightness 图像明亮度的滤镜
contrast 图像的对比度滤镜
drop-shadow 图像的阴影滤镜
grayscale 图像灰度滤镜
hue-rotate 图像色相滤镜
invert 反转滤镜
opacity 透明度滤镜
sepia 深褐色滤镜
saturate 图像饱和度滤镜

可以看到,两者所支持的滤镜种类是一模一样的。

也就是说,它们必然存在诸多差异,下面就让我们逐一探讨。

作用对象的差异

backdrop-filter 最常用的功能,就是用于实现毛玻璃效果。

我们通过实现毛玻璃效果来理解 filterbackdrop-filter 使用上的一些差异。

backdrop-filter 没有诞生前,我们想实现这样一个毛玻璃效果,是比较困难的:

有了它,实现毛玻璃效果就非常 Easy 了,看这样一段代码:

<div class="bg">
    <div>Normal</div>
    <div class="g-filter">filter</div>
    <div class="g-backdrop-filter">backdrop-filter</div>
</div>
.bg {
    background: url(image.png);
    
    & > div {
        width: 300px;
        height: 200px;
        background: rgba(255, 255, 255, .7);
    }
    .g-filter {
        filter: blur(6px);
    }
    .g-backdrop-filter {
        backdrop-filter: blur(6px);
    }
}

CodePen Demo -- filter 与 backdrop-filter 对比

filterbackdrop-filter 使用上最明显的差异在于:

  • filter 作用于当前元素,并且它的后代元素也会继承这个属性
  • backdrop-filter 作用于元素背后的所有元素

仔细区分理解,一个是当前元素和它的后代元素,一个是元素背后的所有元素

理解了这个,就能够明白为什么有了 filter,还会有 backdrop-filter

效果上的差异

下面来看一些实际使用上,效果的差异。

譬如,我们想实现这样一个图片的蒙版 Hover 效果:

使用 backdrop-filter 可以轻松的胜任,因为它就是用于产生蒙版,作用于蒙版背后的元素,其核心伪代码如下:

<div></div>
div {
    position: relative;
    background: url(https://www.wptunnel.com/wp-content/uploads/2021/07/wptunnel-hd-beautiful-wallpaper-4.jpg);
}

div::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    backdrop-filter: grayscale(100%);
    transition: .3s transform;
}

div:hover::before {
    transform: translate(100%, 0);
}

思考如果使用 filter,如何实现上述的效果呢?比较麻烦,因为 filter 是作用于元素上的,所以,它只能是实现类似于这样的 Hover 效果:

上述两个效果 DEMO:CodePen -- filter VS backdrop-filter

核心代码:

div {
    filter: grayscale(100%);
    transition: .3s filter;
}
div:hover {
    filter: grayscale(0);
}

通过这个例子,应该可以更好的理解它们之间的差异。

性能的差异

最早想写这篇文章的初衷,是因为认为 filterbackdrop-filter 可能实际存在性能上的差异。

但是随着我使用多个 DEMO 验证, 利用 filterbackdrop-filter 实现相同的动画效果,获取在动画期间的页面的帧率变化。

除了 Chrome 自带的页面帧率控制面板,还有一种利用 rAF 近似计算页面帧率的方案,可以戳这里 -- Web 动画帧率(FPS)计算

实际对比之后,发现其实两者并无多大性能上的差异。(当然,也可能是我的实验不够严谨。欢迎有更为准确的数据的同学指出)。

因此,如果利用 filterbackdrop-filter 都可以实现同一个效果,仅仅是性能这个角度,两者在性能上其实不会有多大差异,二者选其一即可。

Backdrop Root

接下来这一点很有意思。有必要再好好讲一讲。

当然,这一点 filterbackdrop-filter 都一样,那就是作用了 filterbackdrop-filter 的元素(值不为 none),都会生成 Backdrop Root

什么是 Backdrop Root 呢?(规范戳我 -- CSS 草案 -- Backdrop Root)也就是我们常说的,生成了自己的堆叠上下文(Stacking Context)。

我们直接来看,它会造成什么问题:

生成了 Backdrop Root 的元素会使 CSS 3D 失效

我之前写过一个 3D 球的旋转动画,大概是这样:

这个 Demo 你可以戳这里:CodePen Demo - 3D ball:

然而,如果我们给上述动画的容器,添加一个 filter 或者 backdrop-filter

{
    filter: blur(1px);
}

整个 3D 动画就会坍缩为 2D 动画:

更为具体的探讨,你可以看看我的这篇文章 -- 探究 CSS 混合模式\滤镜导致 CSS 3D 失效问题

作用了 filterbackdrop-filter 的元素会使内部的 fixed 定位失效

另外这个问题也是比较常见的问题。

我们都知道,CSS 中 position: fixed 是相对于屏幕视口进行定位的。

然而,作用了 filterbackdrop-filter 的元素的元素会使得其内部的 position: fixed 元素不再相对于屏幕视口进行定位,而是相对这个 Backdrop Root 元素进行定位,其表现就是 position: fixed 定位的元素退化为了 position: absolute

当然,除了 filterbackdrop-filter 之外,在 CSS 中目前一共有 7 种方式可以让元素内部的 position: fixed 基于该元素定位:

  1. transform 属性值不为 none 的元素
  2. 设置了 transform-style: preserve-3d 的元素
  3. perspective 值不为 none 的元素
  4. will-change 中指定了任意 CSS 属性
  5. 设置了 contain: paint
  6. filter 值不为 none 的元素
  7. backdrop-filter 值不为 none的元素

更为具体的探讨,你可以看看我的这篇文章 -- fixed 定位失效 | 不受控制的 position:fixed

兼容性的差异

最后,我们再来看看兼容性方面的差异。

到今天,不考虑 IE,filter 的兼容其实已经非常非常的好了(2021-12-27):

dropback-filter 则一直没得到 Firefox 系列的支持:

因此,Firefox 的跟进支持一直是阻碍 dropback-filter 在生产环境使用最重要的一环。仅仅从兼容性角度考虑,使用它俩都能实现的效果我们应该尽可能的选择 filter

最后

好了,本文到此结束,希望本文对你有所帮助 :)

想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

@chokcoco chokcoco changed the title 深入探究 filter 与 backdrop-filter 的异同 聊聊 filter 与 backdrop-filter 的异同 Nov 7, 2021
@renmu123
Copy link

renmu123 commented Nov 8, 2021

附上两张兼容性表

image
image

@chokcoco
Copy link
Owner Author

chokcoco commented Nov 8, 2021

@renmu123
啊哈是的,目前制约 backdrop-filter 很大的原因是 firefox 系一直不支持。
兼容性也会补充到文章中~

@chokcoco chokcoco changed the title 聊聊 filter 与 backdrop-filter 的异同 深入探讨 filter 与 backdrop-filter 的异同 Dec 27, 2021
@LavaCxx
Copy link

LavaCxx commented Sep 21, 2022

firefox前阵子的新版本也支持backdrop-filter了,可以放心用,毕竟这属性一般也只是用来整花活,有没有不影响功能使用。
这里再补充一个这两个属性的trick,它两搭配使用可以在激活了hdr模式的页面中使普通元素也带上hdr效果。
详情可见我做的这个demo,用safari打开https://blog.lavac.cc/playground/hdr-pong

@chokcoco
Copy link
Owner Author

@LavaCxx 赞~

@dmwin72015
Copy link

我用NUC8-i5beh 测试了一下,在 4K 输出下,两者的性能差异还是很明显,例如:modal 遮罩层加了 backdrop-filter 会有非常明显的丢帧,而且帧数会调到 30附近, blur 能保持在40左右,丢帧较少。

@journey-ad
Copy link

最近发现一个应该算是bug,svg里foreignObject的backdrop-filter,直接打开预览svg是有效果的,但svg用img标签引入效果就会丢失

@LavaCxx
Copy link

LavaCxx commented Jan 6, 2023

刚刚在测试v站网友的网站时发现一个火狐有关的bug
当子元素套用backdrop-filter且父元素满足overflow不为visibleborder-radius大于0时,类似于position:fixed失效的问题,某些属性会使得backdrop-filter的失效,比如filter(未能复现但却有其事)和transform。简单搜了下几年前的chrome也有类似的问题,但是前人的解决方法在今日的火狐上却无效。

@dongxiaofen
Copy link

dongxiaofen commented Jan 6, 2023 via email

@47547615
Copy link

47547615 commented Jan 6, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants