z-index和transform,你真的瞭解嗎?

z-indextransform是CSS中的屬性,但不多同窗將兩者聯繫到一塊兒,感受他們八杆子打不上。事實真的是這樣嗎?若是你也不能確認,這篇文章就值得你花點時間閱讀。由於閱讀完了,你會有所收穫的。css

堆疊上下文(Stacking Context)

在開始今天的主題以前,先得回憶一下CSS中的Stacking Context(堆疊上下文)。由於只有瞭解清楚了這個概念,才能更好的瞭解下面的內容。html

任何HTML文檔默認的堆疊上下文都是<html>元素。所以,除非建立新的堆疊上下文。默認狀況下,元素的堆疊順序相對於頁面內的其餘元素。在一個未作堆疊順序更換的頁面中,其順序就是根據HTML中的元素出現的前後順序來決定,先出現的在底下,後出現的在頂部。用數字來表示的話是就1,2,3,4,...,n這樣的順序。瀏覽器

 

第二個div作了一個margin-top-50px,能夠看到第二個div遮住了第一個div。那麼怎麼才能改變默認的堆疊順序呢?微信

先把結論給你們拋出來,在CSS中可使用z-indextransform能夠改變元素的堆疊順序。但也可能會致使一些奇怪的狀況,好比具備較大的z-index的元素並不老是位於具備較低z-index元素的上方。好比,在一些狀況之下,同時使用z-indextransform會讓z-index失效等。性能

CSS中會產生新的層狀況還有不少種:

  • 當一個元素位於HTML文檔的最外層(<html>元素)測試

  • 當一個元素被定位了而且擁有一個z-index值(不爲autoflex

  • 當一個元素被設置了opacitytransformsfilterscss-regionspaged media等屬性動畫

  • flex item,也就是父元素的display設置了flex或者inline-flex值,早期的box值不行ui

  • grid item,也就是父元素的display設置了grid或者inline-grid3d

  • isolation:isolate

  • 元素的mix-blend-mode值不爲normal

  • 元素的overflow-scrolling值不爲touch

  • 元素的filter值不爲none

  • 元素的perspective值不爲none

  • 元素的motion-path值不爲none

三維空間

Web中的任何元素都存在於一個三維空間中,除了你們熟知的平面畫布中的x軸和y軸以外,還有控制第三維度的z軸,以下圖所示:

在CSS中使用margin,floatoffset這些屬性,能夠控制元素在x軸和y軸上的表現。而z軸上的表現形式能夠經過z-indextransform來控制。

如何控制z軸

前面也說了,控制z是經過z-indextransform來實現的。先簡單的瞭解一下這兩種控制z軸的方法。

經過z-index控制z軸,須要配合position屬性,且position的屬性值爲relativeabsolutefixedsticky時。而且給z-index顯式的設置數值,數值越大,其層級越高。簡單點說,數值越高,元素越在頂上。

transform能夠經過它的translateZ()來改變元素的層疊順序,其值越大,越在頂層,離屏幕越近。不過經過transform:translateZ()改變元素z軸的層級,必須在元素的父元素中顯示的設置transform-style: preserve-3d或者在transform中顯示的設置perspective()。以下所示:

上面的示例可能還不能明顯的說明translateZ()改變堆疊上下文z軸的順序,由於上面的代碼有position設置,那你要是以爲好奇,能夠看下面這個示例。

示例左邊的元素是沒有設置translateZ,右邊的元素設置了translateZ

有關於z-indextransform更多的教程能夠閱讀下面這些文章:

  •  

z-index 和 translate3d

特別聲明:接下來的內容挑選於@凹凸實驗室的《探究transform動畫元素的z-index》一文。此文章詳細講解了transformz-index在一塊兒使用將會發生的情況。

在一次需求中,須要作出三張卡牌走馬燈式滾動的效果,因爲在前面的一張卡牌須要擋住後面的卡牌,天然而然地就用 z-index 使前面的卡牌顯示在最上面,配以 transform 動畫讓「走馬燈」滾起來,在開發過程當中,在 PC 側 Chrome 中表現良好,在本人手機瀏覽器中也表現良好,最後測試時卻發現,在微信客戶端或 QQ 客戶端中打開頁面出現問題,「走馬燈」滾動時,卡牌先經過transform 就位後,才把 z-index 設置較大的卡牌置於上面,感受上很是的不流暢。

究其緣由,發現這是某些瀏覽器的渲染規則,涉及到 stacking context 的概念,transform 的元素會建立新的 DOM,層級會在普通元素的上面,除了 transform ,還有哪些狀況會建立新 stacking context呢?

下圖是對 transform 和 opacity 的測試結果:

很明顯,紅色 div 都在綠色 div 上面了,說明真的有建立了個更高層級的 stacking context。再作進一步測試,我給兩組的div 都加了 position:relative;z-index:1;,結果綠色的都在上面了,手機微信上也同樣,這能不能說明 z-index 對層級的影響大於 transform 和 opacity 呢。

至於 transform 變換的時候會讓 z-index 「臨時失效」,其實並不是 z-index 失效了,只是 z-index 被用在不一樣的 stacking context 上,而非在默認的 context 上同等地比較層級了。因此 DOM 在 transform 的工程中,DOM 處於一個新的 stacking context 裏,z-index 也是相對於這個 stacking context 的,因此表現出來的實際是 stacking context 的層次,動畫一結束,DOM 又回到默認的 context 裏,這時的 z-index 纔是在同一個 context 上的比較。

那該用什麼方法來控制卡牌的層級,又能讓動畫流暢地表現呢,固然是 translate3d 中的 z-axis,不少時候咱們並不知道它是用來作什麼的,日常用得最多的只是它的 x-axis 和 y-axis,不妨先看個例子:

實際效果是,看不到它們,而後咱們再設置 perspective 爲 201px,這時能夠很明顯地看到,.box2 佔據了整個屏幕,而.box1 寬高約爲 200px,惟有設置 translate3d(0,0,0) 時,寬高才爲 100px

如今能夠來理解下 perspective 和 translate3d 的關係,perspective 能夠比做鏡頭和 DOM 的距離,實際上設置多少都沒影響,由於它經過跟 z-axis 上的數值比例來影響樣式,它更像是一個刻度,而 translate3d 的 z-axis 則表示了 DOM 和屏幕的距離。假定鏡頭跟屏幕的距離固定了,z-axis 越大,DOM 逐漸遠離屏幕,靠近鏡頭,這時 DOM 看起來也就越大,當 z-axis 大於或等於 perspective 時,DOM元素已經在咱們鏡頭的後面了,因此也就看不到它了。

如今也就好理解爲何 perspective 和 translate3d 可以影響 DOM 的層級了,它們在屏幕和鏡頭之間的距離不一樣,因此就有了層次,移動端設備很好地表現了這個結論,但在 PC 的 Chrome 上測試則否則,咱們仍須要 z-index 纔會表現出咱們須要的 層次關係。

transform變換z-index層級渲染異常

在一些瀏覽器或設備上,當transformz-index在一塊兒使用時會發生異樣,形成z-index失靈。至於爲何會失靈,以及如何解決,這裏就很少講了。若是您對這方面的感興趣,能夠看看@張鑫旭大師寫得一篇文章《Safari 3D transform變換z-index層級渲染異常的研究》。

文章總結了兩種解決方案:

  • 方法1:父級,任意父級,非body級別,設置overflow:hidden可恢復和其餘瀏覽器同樣的渲染

  • 方法2:以毒攻毒。也可使用3D transform變換

 

至於怎麼使用3D Transform,你們仍是移步看張大師是怎麼分析的

什麼時候使用Transform來實現z-index

在介紹 z-index 和 translate3d一節中,咱們也瞭解到了,有時候設置z-index來控制z軸並不有效,張大師文章也提到過,它們在一塊兒使用時,有時候會使用z-index失靈。其實還有一個現象,你們可能平時並無注意到。

當你經過z-index配合僞元素::before或者::after時讓其z軸在元素的底部,特別是碰到大的元素渲染(好比全屏背景圖),會直接影響性能,特別是在移動端,會形成客戶端閃退,也就是你們所說的Crash,給用戶形成很是很差的體驗。

縮合上面的幾個現象(固然可能還有不少我本身沒有發現的),咱們能夠拋棄z-index來控制z軸的順序,而是直接經過transform中的translateZ() 或者translate3d()來控制z軸的順序。

總結

單獨使用z-index或者transform中的translateZtranslate3d(),或許你都不會想到他們之間有這麼多的故事,甚至更沒有想到在實際業務中經過transform來替代z-index來控制元素的z軸的順序。那麼這篇文章介紹的就是這二者之間的故事,以及如何經過transform來控制元素z軸的順序。若是文章講解的有不對之處,或者你碰到過更奇葩的現象,以及相關的解決方案,歡迎在下面的評論中與咱們一塊兒分享。

相關文章
相關標籤/搜索