2013年3月9日 星期六

ABC 狗咬豬,CSS 也有 ABCD

事實上我的英文不好
所以這絕對不是英文教學  請大家放心

不知道大家有沒有這種困擾
隨著專案越來越大,CSS 也越寫越多 ( 這個是廢話 )
在這時候,好的設計師會想辦法統一模組


並套用相同樣式
但相同的模組總還是會有幾個需跟其他長不同
而這時該怎麼辦呢?
有兩種解決辦法
  1. 將不同的模組,在定義時加入前層物件的 class id 名稱
  2. 定一套全新的樣式

這兩種做法其實我覺得是種演進過程
原本寫 CSS 最大的目的就是要共用樣式
能共用當然最好,實在越差越多時就該分第二套樣式出來

因此我們先在定義時加入前一層物件的 class 或 id 名稱 (也就是方法 1)
假設是這樣

<style>
   .c1     {color:#f00; ...}
   .c2 .c1 {color:#0f0;} /* 在 .c2 裡面的 .c1 */
</style>

<div class='c1'>I'm c1</div>

<div class='c2'>
   <div class='c1'>Inside c2</div>
</div>


上面就是一個典型的樣式覆蓋
在第二個 <div> 中的字體顏色結果是綠色 (#0f0)
我們來看看實際運作情況:http://jsfiddle.net/culaido/Hqn95/

好,這下問題來了
上面的範例都是以 class 來定義
如果是 id 呢?

<style>
   .c1     {color:#f00; ...}
   .c2 .c1 {color:#0f0;}
 
   #id1 .c1{color:#00f;}
</style>

<div class='c1'>I'm c1</div>

<div class='c2'>
   <div class='c1'>Inside c2</div>
</div>

<div id='id1' class='c2'>
   <div class='c1'>Inside id1</div>
</div>

實際結果: http://jsfiddle.net/culaido/zXVuH/

在這個範例可以發現
第三個 <div> 的樣式定義會有三個衝突
分別是
  1. #id1 .c1
  2. .c2  .c1
  3. .c1

但文字是藍色 (#00f) 
也就代表 #id1 .c1 覆蓋了 .c2 .c1 .c1
但為甚麼他有這種特權呢?

原來這在 W3C 官方文件中
定義了各個選擇器的權重,在發生樣式衝突時
便以各個權重求出的結果決定最後的樣式
文件低家啦:Calculating a selector's specificity (一樣別問我英文在寫啥 = =)
http://www.w3.org/TR/CSS2/cascade.html#specificity

權重的計算方法:style > #id > .class > *
這樣寫大家肯定看不懂
我們來各別講解他們的意義
  • a:  style:將樣式用 style 的方式直接寫在標籤中 (也有人稱行內選擇器)
  • b:  #id:id 選擇器
  • c:  .class:樣式選擇器
  • d:  *:直接以標籤、偽元素或 * 的樣式

舉例來看看

<style>
   .class             {...}   /* a=0, b=0, c=1, d=0 */
   #id .class         {...}   /* a=0, b=1, c=1, d=0 */
   #id .class .class2 {...}   /* a=0, b=1, c=2, d=0 */
   .class div         {...}   /* a=0, b=0, c=1, d=1 */
</style>


這些範例比較簡單,如果看得懂
就可以嘗試挑戰 W3C 官方的範例
 ( 意思是:沒人把 CSS 寫這麼複雜的啦,你沒事把範例搞這麼難做啥 = = )

樣式套用發生衝突時
就從 a 開始往下比
只要前面贏了就不需比下去
樣式便套用贏的那方

也有人用得分來解釋
  • a 代表 1000 分
  • b 代表 100 分
  • c 代表 10 分
  • d 代表 1 分


只總分高的就贏了
再以剛剛的範例來看

<style>
   .class             {color:#f00}   /* a=0, b=0, c=1, d=0 */
   #id .class         {color:#0f0}   /* a=0, b=1, c=1, d=0 */
   #id .class .class2 {color:#00f}   /* a=0, b=1, c=2, d=0 */
   .class div         {color:#ff0}   /* a=0, b=0, c=1, d=1 */
</style>

<div class='class'>
   .class {color:#f00}   /* a=0, b=0, c=1, d=0 */ 
   <div>
      .class div {color:#ff0}   /* a=0, b=0, c=1, d=1 */
   </div>
</div>

<div id="id">
   <div class='class'>
      #id .class {color:#0f0}   /* a=0, b=1, c=1, d=0 */
   </div>
 
   <div class='class'>
      <div class='class2'>
         #id .class .class2 {color:#00f}   /* a=0, b=1, c=2, d=0 */
      </div>
   </div>
</div>
上面實際的結果: http://jsfiddle.net/culaido/eaRdF/
所以這樣就知道樣式發生衝突時
該要以誰為準了吧

=============== 我是中間休息分隔線 ===============

但如果運氣不好
兩個樣式權重相同怎麼辦?

<style>
   #id .class1 {color:#f00}  /* a=0, b=1, c=1, d=0 */
   #id .class2 {color:#0f0}  /* a=0, b=1, c=1, d=0 */
</style>

<div id='id'>
   <div class='class1 class2'>
      我的顏色是甚麼呢?
   </div>
</div>

得分都一樣時
就會以寫在後面的樣式覆蓋掉前面的
所以答案是 綠色 color:#0f0
上面實際的結果: http://jsfiddle.net/culaido/UN6NZ/
大家有猜對嗎?

寫到這裡時我開始懷念我以前的英文老師
雖然學的不好,但有一句話記得很清楚
"凡有規則,就必有例外"

的確,在 6.4.2 !important rules 節中
還有一個 !important 規則  ( 這是潛規則喔 ㄎㄎ )

只要屬性帶有 !important 
則跳過剛剛那些阿雜的權重計算
 !important 的屬性為準
! 不是指程式的 Not 喔 (別搞混了)

<style>
   #id .class1 {color:#f00 !important}   /* a=0, b=1, c=1, d=0 */
   #id .class2 {color:#0f0}              /* a=0, b=1, c=1, d=0 */
</style>

<div id='id'>
   <div class='class1 class2'>
      我的顏色是甚麼呢?
   </div>
</div>

剛剛的範例字就變成紅色
實際範例:http://jsfiddle.net/culaido/2tpSj/

這邊是題外話
雖然 !important 可以超越一切
但實際寫的時候能不用就最好最好不要依靠它
因為如果寫的太氾濫
大家都不想自己的屬性被覆蓋,就變成每個都要寫 !important
就變成沒寫一樣  維護會很頭大

=============== 我是英文不好分隔線 ===============

這期的文字多了些  感謝大家耐心的看完
並敬請期待下期的 CSS Storiainline-block 來一個殺一個 來兩個殺一對

(中華隊 GG 了 T.T)


沒有留言:

張貼留言