探究 CSS 混合模式\濾鏡導致 CSS 3D 失效問題

今天在寫一個小的 CSS Demo,一個關於 3d 球的旋轉動畫,關於 CSS 3D,少不了會使用下面這幾個屬性:

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

這個 Demo 你可以戳這裏,大概是這樣:CodePen Demo - 3D ball:

3dball

嗯,大概到了這個效果,想到了 CSS 混合模式 mix-blend-mode,尋思着,利用混合模式,是否能讓效果更上一層樓或者碰撞出一些其他火花。

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

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章