2013年1月17日 星期四

來談談 z-index


作者:Philip Walton
文章:What No One Told You About Z-Index
http://philipwalton.com/articles/what-no-one-told-you-about-z-index/



看到這篇文章寫得很好,決定用來節錄一下重點

每當 web developer 想要移動HTML上面的元素的前後順序時,第一個直覺都是改變 z-index 數字的大小,但其實 z-index 並沒有想像中這麼簡單。

這個作者請你做了一個實驗,下面是一個簡單的區塊堆疊應用

Check out this Pen!
你要如何讓紅色的區塊被壓到最下面,但你不能

  • 不能改變 HTML 結構
  • 不能修改 z-index 大小
  • 不能修改 position 的值

想到結果了嗎?

Check out this Pen!

你猜對了嗎? 作者只加了一段CSS

div:first-child {
  opacity: .99;
}


如果你感到非常疑惑,不要氣餒,因為作者告訴你:W3C的 z-index 規則 其實真的很複雜!


堆疊的規則

當 z-index 跟 position 屬性沒有共同存在的時候,元素堆疊的規則可以說是簡單的,就是HTML堆疊的先後。

當 position 屬性存在的時候,任何有 position 的元素會顯示在,沒有position的元素前面 (意思是除 static 之外的 position 屬性,relative、absulute....)

當z-index 跟 position 共同存在的時候,這規則就難了,我把作者整理的順序放在下面

由後往前排序是這樣:
  1. The stacking context's root element
    堆疊內容的 root 元素
  2. Positioned elements (and their children) with negative z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)
    有 position 屬性的元素(包含子元素) + 負數的 z-index 值 (數字越大越前面)
  3. Non-positioned elements (ordered by appearance in the HTML)
    沒有 position 屬性的元素
  4. Positioned elements (and their children) with a z-index value of auto (ordered by appearance in the HTML)
    有 position 屬性的元素(包含子元素) + z-index:auto 
  5. Positioned elements (and their children) with positive z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)
    有 position 屬性的元素 + 正數 z-index 值(數字越大越前面)


最後,作者說明了上面的例子,整體的順序到底是怎麼改變的

原本的順序是這樣的:
<div><!-- 1 -->
  <span class="red"><!-- 6 --></span>
</div>
<div><!-- 2 -->
  <span class="green"><!-- 4 --><span>
</div>
<div><!-- 3 -->
  <span class="blue"><!-- 5 --></span>
</div>
經過修改後的順序變成這樣:
<div><!-- 1 -->
  <span class="red"><!-- 1.1 --></span>
</div>
<div><!-- 2 -->
  <span class="green"><!-- 4 --><span>
</div>
<div><!-- 3 -->
  <span class="blue"><!-- 5 --></span>
</div>
原本CSS的寫法,我們只有兩層的堆疊內容,root 跟 span.red
當我們在 span.red 的父層 div 設定了透明度 opacity:.99 (div:first-child { opacity: .99; })
我們讓原本的堆疊變成了三層
第一個 div 跟他的子元素都不會吃到 .red 的 z-index 跟 position
他們變成沒有 position 跟 z-index 的元素了
他們的堆疊順序變成按照原本的 HTML 的結構來計算
所以作者用 1 跟 1.1來代表他們後來變成的順序


感謝這位作者,我看完這篇文章頭都昏了,但也終於弄懂 z-index 的層級判別方式

請不再在隨便相信文章裡面寫「這是 z-index 的 bug」了!