1. 程式人生 > 其它 >前臺開發從頭說起:理解css盒模型

前臺開發從頭說起:理解css盒模型

在掌握了豐富而強大的css選擇符之後,就具備了將css樣式根據需要應用到網頁中任何元素的能力。能夠應用規則了,接下來就需要熟練掌握規則的制定方法——什麼樣的屬性組合能夠實現什麼樣的效果。一般的顏色、字型、字號、行高等的設定比較容易掌握,而初學者在應用css的時候,主要頭疼的還是如何用css實現複雜的網頁佈局,從兩欄佈局、三欄佈局,到表單設計等。在佈局的時候,實際上主要是藉助元素的寬、高、定位、浮動、邊距、邊框、間距、背景顏色、背景圖片的組合來實現的。而所有這些,都要基於對css盒模型的理解。網上對盒模型的論述很多(推薦閱讀《徹底理解css盒子模式》),我這裡想從實用的角度來談談。

網上有兩張著名的圖片,分別以2D和3D的形式描述css盒模型:

通過這兩張圖,一般來說對於margin、border、background-color、background-image、padding以及width和height有較直觀的瞭解了。

更為重要的是要了解以下幾點:

  1. 對於所有以“塊(block)”方式呈現的元素都具備這個模型的特性,而不只是div;
  2. margin是以所指定元素的父級元素(常稱為“容器”)為基準的;
  3. 一個元素(通常為塊元素)在頁面中所佔的位置尺寸為:寬度= width + padding-left + padding-right + border-left-width + border-right-width + margin-left + margin-right
    ;高度 = height + padding-top + padding-bottom + border-top-width + border-bottom-width + margin-top + margin-bottom;(部分瀏覽器有差異,以後再具體討論);
  4. background-color將填滿border內部的全部範圍;background-image預設以圖片左上角對齊border內部左上角點,然後完整顯示整個圖片(超出部分不予顯示),如果圖片尺寸不足鋪滿整個範圍,圖片預設重複自己直至鋪滿或超出範圍;
  5. background-image將疊加到background-color之上;通過指定圖片的對齊方式,可以改變background-image的位置;

通過以上這些規則的組合,就能在有限的元素組合下,實現各種修飾性效果。一個簡單的例子如下:

將一個15畫素高,顏色為#c00的純色圖片

放入一個高度為30畫素,背景色為#f00的塊元素,設定圖片在Y軸方向不平鋪,在x軸方向平鋪。結果得到一個類似下圖的效果:

這是簡單的由背景色與背景圖組合實現的效果。根據這樣的原理,當我們的文件結構有兩層時,例如:<a href=”#"><span>文字</span></a>,我們可以通過由a元素的背景顏色圖片和span元素的背景顏色圖片組合,從而得到較為複雜的效果,例如:

這個按鈕效果,用純圖片很容易實現,但是用圖片實現就會面臨一個問題:不通用。如果要通用,應該把文字和背景圖片分離開來,同時,由於文字有多有少,因此按鈕的寬度要是可變的,但是按鈕並不是從左到右完全一致的背景,於是不能使用一張圖片進行橫向平鋪,按照以前的做法,可能會使用一個一行三列的表格,第一個單元格放入左側的圖片,中間的單元格放文字和平鋪的背景,右邊的單元格放右側的圖片。這種思維傳遞到了“div+css”佈局思維模式下,於是就出現了這樣的結構:

<div class=”button”><div class=”left”></div><div class=”center”></div><div class=”right”></div>

這個結構的出現,就是為了實現自適應寬度的按鈕,今天依然存在。實際上,使用上面的a+span的基本結構,就能實現這個效果。將中間平鋪部分和左側或右側的邊緣圖片組合在一起,重複部分做得寬一些,作為a的背景圖片,把另一側的圖片作為span的背景圖片覆蓋到a的背景圖片上。組合起來看上去就成為一個整體。程式碼如下:

效果如下:

a {display:block;width:200px;height:36px;background:url(button.gif) no-repeat right bottom;}
a span {display:block;line-height:36px;background:url(button.gif) no-repeat left top;color:#fff;text-decoration:none;text-align:center;}

用到的背景圖片如下:

這個例子很簡單,但是需要對“背景組合”有足夠的理解,能夠想到應用。而要想到如此應用,首先是對於盒模型中的“background”足夠的理解。否則,就只會想到三個div(或者其它元素組合方式),但是由於左右兩個結構完全一樣,為了區分它們,只好使用class或者id來標記。這就是我在上一篇中所提到的不必要的class和id。

除了利用display:block讓行內元素改變為塊元素從而使用盒模型特徵外,在浮動的時候,也經常會用到盒模型的一些特徵。再舉個例子:

使用浮動佈局的時候,並列呈現的浮動元素中的第一個如果設定與浮動方向相同的margin,則IE 6下會出現margin加倍的bug(這就是著名的IE6浮動邊距加倍bug)。為了解決這個問題,很多人喜歡給一組浮動元素的第一個加上class=”first”,從而可以對這個元素單獨應用樣式。或者對這一組浮動元素加上display:inline的屬性以解決這個bug。

上述兩種方式都是沒有使用hack選擇符或者類似“_margin”這樣的非標準屬性的很好的hack方式。但是,如果不是非用margin不可,只要使用padding來代替margin,就能解決這個問題。或者採用與浮動方向相反的margin也可以。不需要任何額外的hack。這也是在充分理解盒模型的基礎上,由於對這個bug的瞭解,從而在實現樣式的時候直接避開,而不是出現了之後再用額外手段去hack。

對盒模型的理解,除了margin、border、padding、width、height五大屬性以及兩種背景的應用之外,還要了解父級元素與子元素之間的關係。比如父元素沒有設定尺寸,而對子元素設定margin-top屬性,在某些瀏覽器下,本來是想針對父元素的邊緣設定margin,結果margin被設定到了父元素之外,造成父元素與外部元素的margin。這種情況,將子元素的margin改成父元素的padding,也可以在不改變表現的情況下實現相同的效果。

要想通過對盒模型特徵的充分應用來減少css中的hack使用,或者以更簡潔的程式碼實現更復雜的效果,需要對盒模型不斷地嘗試和總結。這是《css權威指南》之類的經典鉅著也沒法教給你的。

只有越理解盒模型,才能越好地利用浮動和定位來實現複雜、精確的佈局。關於浮動的問題,下一次我們再一起來了解一下。