探究 CSS 混合模式\滤镜致使 CSS 3D 失效问题

今天在写一个小的 CSS Demo,一个关于 3d 球的旋转动画,关于 CSS 3D,少不了会使用下面这几个属性:git

{
    transform-style: preserve-3d;
    perspective: 1000;
    transform: translate3d();
}

这个 Demo 你能够戳这里,大概是这样:CodePen Demo - 3D ball:github

3dball

嗯,大概到了这个效果,想到了 CSS 混合模式 mix-blend-mode,寻思着,利用混合模式,是否能让效果更上一层楼或者碰撞出一些其余火花。chrome

mix-blend-mode:咱们一般称之为混合模式,利用混合模式将多个图层混合能够获得一个新的效果, mix-blend-mode 描述了元素的内容应该与元素的直系父元素的内容和元素的背景如何混合。

关于混合模式的一些使用能够看这里:难以想象的混合模式 background-blend-mode (二)难以想象的混合模式 background-blend-mode数组

CSS 3D 配合 mix-blend-mode

然而,给元素加上了一个混合模式以后,神奇的事情发生了,3D 效果消失了。浏览器

也就是在每一个光点的 CSS 元素代码中添加这样一句:缓存

{
    mix-blend-mode: lighten;
}

3dball2

效果从 CSS 3D 变成了 2D工具

qq 20181217194534

这就很蹊跷了,预想中的混合并无发生,取而代之的是 3D 的失效。我想,也许与内核有关,上面的效果是在 chrome 65.0.3325.181 试验获得的。测试

是否与浏览器内核有关?

带着这样的疑问,我又测试了下其余几个内核:动画

  • firefox 64.0 -- 此次更加诡异,整个图案都不会再被渲染出来
  • Safari 12.0.2 -- 渲染正常

Safari 是能够正常展现的,只能初略的认为,应该是与内核有关系的。那应该也有不少人遇到过一样的问题,带着这个疑惑,google 一下。网站

爆栈网也有同窗提出相似的疑惑:StackOverflow -- mix-blend-mode is broken by 3D transformations on page

image

随后,在 chromium bug 提交网站上,找到了 15 年的一个 bug 单,也是对这个问题的疑问:

BUG -CSS mix-blend-mode turns off CSS perspective.

最终在 bug 单的最下面找到了可能靠谱的回答:

When we have mix-blend-mode, the closest ancestor that creates stacking context will isolate blending. We create a render surface at the root of this isolated group and because render surfaces don't support preserve-3d(because they render into separate FBO), we see a flattened result.

ajuma@ suggested that this bug maybe much easier to fix after Slimming paint v2 if we can somehow disentangle transforms from layers.

翻译一下,意思大概是:当咱们使用 CSS 混合模式的时候,堆叠上下文会从新对这个使用了混合模式的元素的根节点处建立一个独立的渲染平面,可是很惋惜,这个渲染平面是不支持 preserve-3d 的(由于它们渲染到单独的FBO中),因此咱们看到是一个 2D 的平面效果。

验证 Layer borders

上面的那句话应该已经能够做为结论,我再使用 chrome 提供的工具验证一下,打开开发者工具的 Rendering -> Layer borders:

image

黄色表明 CSS 渲染时候的 GraphicsLayer 层, 蓝色网格表示瓦片(tile),你能够把它们看成是层的单元(并非层),Chrome 内核能够将它们做为一个大层的部分上传给 GPU 进行渲染加速。

  • 正常 3D 模式下,开启 Layer borders 效果:

balllayer

  • 添加了 mix-blend-mode 的 3D 模式下,开启 Layer borders 效果:

balllayer2

能够看到,在 mix-blend-mode 的 3D 模式下,确实在整个球形元素以外,又多了一层蓝色 tile。也就是上文提到的独立的渲染平面,也就是由于这个渲染平面不支持 preserve-3d 的缘由,咱们最终获得了一个 2D 平面图形。

滤镜也会致使 CSS 3D 失效

完了吗?没有。不是吧,这谁顶得住啊。

qq 20181218111248

那么若是是由于 mix-blend-mode 多生成了一个独立渲染平面致使的 3D 失效,那么是否有其余元素也会致使一样的结果呢?

带着疑惑,去掉了 mix-blend-mode,我又给设置了 3d 的元素添加了一个滤镜:

{
-    mix-blend-mode: lighten;
+    filter: blur(1px);
}

果真,出现了一样的问题,3D 失效:

balllayer3

总结一下

嗯。那么应该能够初步获得一个结论就是全部这些在渲染时候须要再独立生成一个渲染平面,且包含了 preserve-3d 的属性,都会致使内部的 CSS 3D 失效

暂时我发现的有下述几个属性,都会致使 CSS 3D 失效:

  • mix-blend-mode
  • background-blend-mode
  • filter

其余问题

这个 bug 有什么影响

额,一般来讲,不多会有人在使用 CSS 3D 的同时使用混合模式或者滤镜,这两个属性更多的锦上添花的做用,因此大部分时候,不使用它们就不会有问题, 因此影响不是很大。

上文中的 FBO 是什么?

上文的 FBO 准确而言是什么我也没法 100% 肯定,推测应该是 Frame Buffer Object,帧缓存对象,存在于显存中。帧缓存是一些二维数组和 OpenGL 所使用的存储区的集合:颜色缓存、深度缓存、模板缓存和累计缓存。

各类三维场景如今渲染到屏幕上都是先放到一个 FBO 中,能够理解为一张离屛图片,用于加速渲染。

Bug 什么时候会被修复

在 chromium bugs 网站,上述 bug 被合并到 issue 575099,而且最终状态是 Untriaged,表示还没有分配优先级,意思是等待某人肯定哪一个人应该认领并修复该特定错误。因此,短时间内可能无望解决。

最后

感谢耐心读完。更多精彩 CSS 技术文章汇总在个人 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

好了,本文到此结束,但愿对你有帮助 :)

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

相关文章
相关标签/搜索