2013年2月3日 星期日

.clearfix 的前世今生

咳~咳~
繼上回的 [ float 的新朋友 clearfix 與 clear 的三腳關係 ] 後
再讓我們來看看故事是怎樣發展下去的

傳說中 .clearfix 也不是一開始就長得這樣的
他的人生有起有伏 跌跌撞撞
而這是他目前的模樣  ( 來自於 bootstrap http://twitter.github.com/bootstrap/ )
<style> 
   .clearfix:before,
   .clearfix:after {
      display:table;
      line-height:0;
      content:"";
   }
   .clearfix:after {
      clear:both;
   }
   .clearfix {
      *zoom: 1;
   }
</style>

.clearfix 裡面有 pseudo classafter 相信有認真看上一篇的同學不會有問題
但為什麼要有 before 呢

過去在 CSS 大神們的研究下
大家都認同清除浮動的最佳方式是利用 .clearfix 的做法
現今眾多 framework 也都有相關的 class
舉例來說:
  1. jQuery UI 是 .ui-helper-clearfix
  2. bootstrap 就是 .clearfix
但在不曉得該怎樣寫的那時候
第一代 .clearfix 誕生了
<style> 
  .clearfix:after {
    content: ".";  /* 作為一個隱形的牆,裡面塞甚麼其實都可以 */
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
  }
  .clearfix { zoom: 1; } /* IE 5.5/6/7 */  (註1)
</style>

可怕的事情發生了
Thierry Koblentz 大大描述這種寫法有瀏覽器顯示不同的問題  ( 又是 IE 又是 IE = = )
原文網址  http://www.tjkdesign.com/articles/clearfix_block-formatting-context_and_hasLayout.asp

這其實是因為 區塊級元素 ( block ) 和 邊界 ( margin ) 暗地有一個密約
只要是母子區塊中有同方向的 垂直邊界  ( margin-top or margin-bottom )
就可能導致其中一個 垂直邊界 消失 !!

這是 HTML 架構 ( 還有很多種情況也會發生,但挑最好理解的 )
圖中的 parentchild 都是示意而已
請把它看成隱形的註解 ^^
<div style='margin-top:10px'>
   Parent
   <div style='margin-top:60px'>   
      Child
   </div>
</div>




原來在 W3C 的規格書中,已經說明了這種情況的處理方式
這稱之為 邊界重疊 ( Collapsing margins )
http://www.w3.org/TR/CSS21/box.html#collapsing-margins


















要發生邊界重疊其實是需要一些條件的,無限精簡來說
  1. 只有重疊的垂直邊界會發生
  2. 如果母元素具有 (border, overflow) 的話不會發生
  3. 和一些較細,不易遇到的部分 ( 就是不好解釋,遇到你就知道了 ^^!!) ...etc 
發生邊界重疊時新邊界的計算方式則變成
  1. 如果 2 個 margin 都是正數,則挑最大的
  2. 如果有正有負的時候,則是取相加後的結果
  3. 如果 2 個 margin 都是負數,則挑絕對值最大的,然後從 margin 0 的位置,向反方向位移
所以他們得出了結論

























Chrome, Firefox, Safari 等瀏覽器中會長的像下圖這樣子
Childmargin 會突破 Parent 的上緣  直達天際啦

























但是在 IE 中是怎麼顯示的呢 ?




































其實寫 CSS 最麻煩就是遇到瀏覽器顯示不一
尤其是按照規格書來寫的 code 的話,
讓人無所適從

為了讓大家顯示相同
.clearfix 必須要想辦法讓邊界重疊不會發生
剛剛有提到 邊界重疊 不會發生在 Parent 具有 overflowborder 的物件上
但總不能每個 物件都寫一個透明 border 吧,這樣寬高計算上也很麻煩

另外清除浮動還有一種做法
就是在浮動區塊的母元素裡加上 overflow : (auto | hidden)
但這有另外的缺點

不管是 autohidden 都會造成排版上的困擾
說到底物件的大小很多都是靠內容物決定的
把他裁了或跑出捲軸不就糗了嗎

尤其 CSS 3 的陰影效果又特別多
超過物件被裁了不就甚麼都看不到了嗎

而到了最後由 Nicolas Gallagher 大大提出更簡單更直覺的做法
又稱 micro clearfix
原文網址:http://nicolasgallagher.com/micro-clearfix-hack/
也是目前 .clearfix 的原型
他是這樣子的
   
<style>
   .cf:before, /* cf 是 clearfix 的縮寫,不是我的縮寫喔 = = */
   .cf:after {
       content: " "; 
       display: table;
   }

   .cf:after {clear: both;}
   .cf {*zoom: 1;}
</style>

既然最下面都有一個無形的牆了,最上面加一個也是合情合理的吧 = =
Margin 在這兩堵牆的保護下
就能夠保護不會發生 邊界重疊 的現象了

現在的 .clearfix 基本是這個方式來改造的
都常是因為不希望這兩堵牆有實際佔的空間
所以加上 line-height 設為 0px 而已



又到了故事的尾聲了,感謝收看本期的內容
並敬請期待下期的 CSS 的故事: 放開那張圖片,神秘的 overflow 大功用


=============== 我是神奇分隔線 ===============

其實母子區塊的 邊界重疊 不易發生
因為對於母子區塊來說
正確的做法是母區塊用 padding 將上面的空間空出
怎麼也不會用子區塊去 margin

較常發生的是在區塊相鄰的情況下
下面的有 magin-top 上面的有 magin-bottom
該重疊的部分就會看到 IE 莫名其妙空間空非常大


註1:
zoomIE 獨有的 css 屬性,功能如同其名,能夠放大指定的物件
但其際上誰會需要那種功能 ( 圖片直接放大失真多嚴重你甘災 )

反而通常都拿來解 IE 顯示上的問題
zoom 會觸發 IE rendering enginehasLayout
可在 IE 的 CSS 根本沒寫錯但顯示不正常的情況下,重畫物件區塊讓顯示正確 = =

邊界重疊 DEMO ( IE 要用小於 7 的版本喔 )
   http://jsfiddle.net/necolas/QZXS6/


W3C CSS 速查字典
  邊界 ( margin ) http://www.w3schools.com/css/css_margin.asp
  超出 ( overflow ) http://www.w3schools.com/cssref/pr_pos_overflow.asp

呃明确:机器人

沒有留言:

張貼留言