探究 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 訂閱收藏。

好了,本文到此結束,但願對你有幫助 :)

若是還有什麼疑問或者建議,能夠多多交流,原創文章,文筆有限,才疏學淺,文中如有不正之處,萬望告知。

相關文章
相關標籤/搜索