## 3.1 理解盒模型
其實 HTML 頁面中每個元素其實都是一個「盒子」,默認情況下這些盒子的邊框不可見,背景也是透明的,所以我們不能直接的看到頁面中盒子的結構,但是我們可以借助一些 Web Developer 工具條可以方便地顯示盒子的邊框和背景,讓我們能很直觀的看到這些盒子的結構。
每個盒子都有三組屬性:
* 外邊距(margin): 可以設置盒子與相鄰盒子之間的距離。
* 邊框(border): 可以設置邊框的寬度、樣式和顏色。
* 內邊距(padding):可以設置盒子內容區和邊框之間的距離。
一個盒子有四條邊,所以這些屬性也各有四個屬性,分別是上(top)、右(right)、下(bottom)和左(left),為了更直觀的了解盒模型的結構,這里放上一張盒模型的結構圖:

盡管這三組屬性共有 12 個屬性值,但我們也可以對它們進行簡寫,這里以?`margin`?為例:
~~~
margin-top:1px;
margin-right:1px;
margin-botton:1px;
margin-left:1px;
~~~
縮寫后的代碼如下:
~~~
margin:1px 1px 1px 1px;
~~~
縮寫的順序是上 -> 右 -> 下 -> 左,順時針的方向。相對的邊的值相同,則可以省掉,代碼如下:
~~~
margin:1px;// 四個方向的邊距相同,等同于margin:1px 1px 1px 1px;
margin:1px 2px;// 上下邊距都為1px,左右邊距均為2px,等同于margin:1px 2px 1px 2px
margin:1px 2px 3px;// 右邊距和左邊距相同,等同于margin:1px 2px 3px 2px;
margin:1px 2px 1px 3px;// 注意,這里雖然上下邊距都為1px,但是這里不能縮寫。
~~~
### 3.1.1 盒子的邊框(border)
邊框(border)有四個相關屬性:
* 寬度(border-width):可以使用 thin、 medium 和 thick 等文本值,也可以使用**除百分比和負值以外**的任何絕對值。
* 樣式(border-style):有 none、 hidden、 dotted、 dashed、 solid、 double、 groove、 ridge、 inset 和 outset 等文本值。
* 顏色(border-color):可以使用任何顏色值,包括 rgb、 hsl、十六進制顏色值和顏色關鍵字。
* 圓角(border-radius):屬于 CSS3 新增屬性,可使用百分比、相對值和絕對值。
> CSS 推薦標準并沒有明確規定 border-width 的幾個文本值的確切寬度,所以實際寬度會因瀏覽器而異。
> border-radius 不影響盒子的定位。
### 3.1.2 盒子的內邊距(padding)
內邊距是盒子內容區與盒子邊框之間的距離。在沒有設置內邊距的情況下,內容緊挨著邊框:

設置內邊距后,內容區與邊框有一定的距離(padding 的大小):

### 3.1.3 盒子外邊距(margin)
與內邊距和邊框相比,外邊距就要顯得復雜的多了,首先是外邊距疊加,**垂直方向上的外邊距會疊加**,例如有三個段落應用了如下規則:
~~~
p {
height:50px;
border:1px solid #000;
background: #fff;
margin-top: 50px;
margin-bottom: 30px;
}
~~~
由于第一段的下邊距與第二段的上邊距相鄰,你可能會覺得它們兩個盒子邊框之間的外邊距只和是 80px,但實際上是 50px,像這樣上下外邊距相遇時,它們會相互重疊,直到一個外邊距碰到另一個盒子的邊框。就上面例子而言,第二段較寬的上外邊距會碰到第一段的邊框,也就是說較寬的外邊距決定兩個盒子之間的距離。

### 3.1.5 外邊距的單位
在設置段落文本外邊距時應該注意,為了避免因增大字號導致段落間外邊距不變引起的整體不協調的問題,在設置段落的上下外邊距是應該使用?`em`?單位,這樣當字體大小調整時,段落的上下外邊距也會根據字體的大小來調整距離,這樣頁面的整體布局就會比較協調一致,而左右外邊距則可以用?`px`?絕對單位,確保左右外邊距不會因字體大小的調整而發生改變,比如可以這么設置:
~~~
p {
font-size: 1em;
margin: .75em 30px;
}
~~~
這樣段落垂直距離就會始終保持字體高度的四分之三的高度,水平外邊距不會因字體的調整而發生改變了。
## 3.2 盒子有多大
作者在本章介紹了塊級元素和行內元素的不同行為。
### 3.2.1 沒有寬度的盒子
作者在這一節中專門提到了一個 「沒有寬度」的概念:沒有顯式地設置元素的?`width`?屬性。如果不設置塊級元素的?`width`?屬性,那么這個屬性的默認值就是?`auto`?,結果就是會讓元素的寬度擴展到與父元素同寬,對于塊級元素和行內元素更具體的介紹請看筆者的上一篇文章[CSS 設計指南 學習筆記 一](http://www.cleardesign.me/stylin-with-css-note-1)。
盒模型結論一:
> 沒有設置寬度的元素始終會擴展到填滿其父元素的寬度為止,添加水平外邊距、水平邊框和水平內邊距都會導致內容寬度的減少,減少量等于水平外邊距、水平邊框和水平內邊距的和。
### 3.2.2 有寬度的盒子
盒模型結論二:
> 為設定了寬度的盒子添加外邊距、邊框和內邊距,會導致盒子擴展的更寬,實際上,盒子的?`width`?屬性設定的只是盒子內容區的寬度,而不是盒子要占據的( margin-left + border-left + padding-left + width + padding-right + border-right + margin-right )水平寬度。
所以一定要記住的是,給設定了?`width`?的元素添加外邊距、邊框和內邊距所展示的行為與默認的?`auto`?狀態下的行為會有截然不同的表現。
拓展:
但是與布局相關的元素大部分都同時設置了?`margin`、?`border`、?`padding`?和?`width`,這就導致了在布局時的各種計算保證總寬度( margin-left + border-left + padding-left + width + padding-right + border-right + margin-right )保持不變,這樣不僅麻煩,有的時候還比較容易出錯,為了解決這一問題, CSS3 新增了一個?`box-sizing`?屬性,通過它可以將設置了?`width`?的元素也設定成具有默認的?`auto`?狀態下的行為。這樣就省去了許多計算?`width`?的時間,同時也不會出錯,而且它的瀏覽器支持情況也是一片大好( 除了 IE 6 和 IE 7 不支持,其他個別老版本的瀏覽器需要添加瀏覽器私有前綴才支持 )。
可以這樣使用這個屬性:
~~~
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
~~~

## 3.3 浮動與清除
浮動和清除是頁面布局的一大利劍,分別是?`float`?和?`clear`,浮動可以讓原來上下堆疊的塊級元素變成左右并列,可以實現文字繞圖片排列效果。浮動的元素會脫離常規的文檔流,原來緊跟其后的元素會在空間允許的情況下向上提升到與浮動元素平起平坐。如果浮動元素后面有兩個段落,而你只想讓第一段與浮動元素并列(就算旁邊還能放下第二段,也不想讓它上來),就可以使用?`clear`?屬性清除浮動。
### 3.3.2 圍住浮動元素的三種方法
浮動元素脫離了文檔流,所以我們看不到包含它的父元素了,這種情況有時候并不是我們想要的,所以作者在本章介紹了如何圍住浮動元素的三種方法。
方法一:為父元素添加?`overflow: hidden;`?強制它包圍浮動元素。
這種方法在某些情況下也不適用,比如通過浮動設置的水平排列的菜單,對其父元素設置?`overflow: hidden;`?后,盡管父元素圍住了它,但是如果菜單有下拉選項的話,當鼠標移動到上面的時候下拉菜單并不會顯示,因為設置了?`overflow: hidden;`,所以超出父元素范圍的內容都被隱藏掉了。
方法二:同時浮動父元素
父元素設置浮動后,不管其子元素是否是浮動,父元素都會緊緊地包圍住它的子元素,因此需要用?`width: 100%;`?再讓父元素的寬度與瀏覽器容器同寬。同樣,盡管父元素圍住了它,但是這樣會導致頁面中出現大量的浮動元素,而浮動元素有往往不好控制,并不利于頁面的布局。
方法三:添加非浮動的清除元素
第三種強制父元素包含其浮動的子元素的方式就是給父元素的最后添加一個非浮動的子元素,然后清除該子元素,因此父元素一定會包含這個子元素以及前面的浮動元素:
~~~
// HTML
<section>
<p>It's fun to float</p>
<div class="clearfix"></div>
</section>
// CSS
p {
float: left;
}
.clearfix {
clear:both;
}
~~~
盡管這個方法能解決上面提到的兩種方法中的問題,但它還不是最好的方法,因為它會在文檔中添加無意義的標簽,這違反了標簽語義化的規則,對搜索引擎并不友好。所以如果你要清楚浮動但既不想浮動父元素又不想對父元素設置?`overflow: hidden;`?也不想增加無意義的標簽的話,可以使用偽元素來清除浮動:
~~~
.clearfix::after {
content: " ";
display: table;
clear: both;
}
~~~
然后在父元素中添加?`clearfix`?類,因為搜索引擎并不會抓取偽元素,所以這種方法并沒有增加無意義的標簽,這里應該注意的是,CSS3 標準是用兩個冒號來區別偽元素和偽類,而 CSS2.1 中不管是偽元素還是偽類都是用單個冒號表示,然而 IE8 并不支持雙冒號的偽元素,所以問題就來了,如果你要遵循 CSS3 的標準使用雙冒號的話就不兼容 IE8 了,如果使用但冒號的話又不符合 CSS3 標準規范,當然現在大多數還是使用但冒號的,選擇哪種還是看個人的選擇。
## 3.4 定位
CSS 布局的核心是?`position`?屬性,對元素應用這個屬性可以相對于它在常規文檔流中的位置重新定位,`position`?屬性有 4 個值:?`static`、?`relative`、?`absolute`?和`fixed`。
### 3.4.1 靜態定位(static)
靜態定位下的塊級元素會在默認文檔流中上下堆疊,想要突破?`static`?定位提供的這種按順序布局元素的方式,就必須對元素的?`position`?屬性的值改為其他三個值。
### 3.4.1 相對定位(relative)
所謂的相對定位就是相對于元素原來的位置(static 狀態下的位置)進行定位,也就是說在不設置?`top`、?`right`、?`bottom`?或?`left`?的話,和它在默認(static)情況下的表現是相同的,但是如果對它設置了?`top`、?`right`、?`bottom`?或?`left`?的話,就會相對與它默認的位置進行定位。相對定位的元素可以遮住靜態(static)定位的元素。可以給?`top`和?`left`?屬性設定負值,把元素向上和向左移動。
### 3.4.2 絕對定位(absolute)
絕對定位跟靜態定位和相對定位是絕對不一樣的,靜態定位和相對定位并不會脫離文檔流,會占居原來的位置,而絕對定位會把元素徹底從文檔流中拿出來,然后再相對于其他元素(這里的其他元素指的是定位上下文,默認是?`body`?元素)定位。
絕對定位的一個重要的概念就是**定位上下文**,把元素的?`position`?屬性設定為?`relative`、?`absolute`?或?`fixed`?后,繼而可以使用?`top`、?`right`、?`bottom`?和?`left`?屬性,相對于「另一個元素」移動該元素的位置。這里的「另一個元素」就是該元素的定位上下文。
絕對定位的默認定位上下文是?`body`,這是因為?`body`?是標記中所有元素的唯一的祖先元素,而實際上,絕對定位元素的任何祖先元素都可以成為該絕對定位元素的定位上下文,只要把相應的祖先元素的?`position`?屬性的值設定為?`relative`?即可。
### 3.4.3 固定定位
從完全脫離文檔流的角度說,固定定位與絕對定位類似。但不同之處在于,固定定位的定位上下文是視口(瀏覽器窗口),因此它不會隨頁面的滾動而移動。最常見的情況是用它來創建不隨頁面滾動而移動的導航元素。
## 3.5 顯示屬性
`display`?屬性的值很多,但常用的除了前面提到的控制塊級元素、行內元素和行內塊級元素的?`block`、?`inline`?和?`inline-block`?以外,還有一個比較常用的就是?`none`,把元素的?`display`?屬性的值設定為?`none`?后,該元素及所包含在其中的元素,都不會在頁面中顯示。他們原先戰局的所有空間都會被「回收」,就好像相關元素根本不存在一樣。
與此類似的屬性還有?`visibility`,這個屬性常用的兩個值是?`visible`(默認值) 和?`hidden`,把元素的?`visibility`?屬性的值設定成?`hidden`?,元素會被隱藏,但它還會占據頁面中原來的空間位置。
筆者覺得有點類似定位中?`absolute`?和?`relative`?的感覺,就是?`absolute`?定位的元素的原來的位置會被「回收」(脫離文檔流),就好像元素根本不存在一樣(指的是原來占據的位置不存在一樣),`relative`?定位的元素還會占據頁面中原來的空間位置。
## 3.6 背景
背景支持為元素添加背景顏色也背景圖片。
### 3.6.1 CSS 背景屬性
CSS 規定以下與背景相關屬性:
~~~
background-color: ; // 背景顏色
background-image: url(); // 背景圖片
background-repeat: ; // 背景重復
background-position: ; // 背景位置
background-size: ; // 背景尺寸 CSS3 新增屬性
background-attachment: ; // 背景粘附
background-clip: ; // 背景
background-origin: ; // 背景
~~~
### 3.6.5 背景位置
~~~
background-position:關鍵字 px em 百分比;
~~~
用于控制背景位置的?`background-position`?屬性,是所有背景屬性中最復雜的。`background-position`?有 5 個關鍵字值:?`top`、?`right`、?`bottom`、?`left`?或?`center`,這些關鍵字值任意兩個組合起來都可以作為該屬性的值。比如?`top`?`right`?表示把圖片放在元素的右上角位置,`center`?`center`?表示把圖片放在元素的中心位置。除了這些關鍵字值以外還可以用百分比、`px`?和?`em`?等單位。
拓展
要是只設置一個值,則將其用來設定水平位置,而垂直位置會被設為?`center`。
在使用**關鍵字**和**百分比**的情況下,情況有點特殊,設定的值會同時應用于元素和圖片,也就是說,如果設定了?`80%`?`20%`,則圖片水平?`80%`?的位置與元素?`33%`?的位置對齊,垂直方向也一樣,如下圖:

其他單位數值就不一樣了,如果用像素單位來設定位置:
~~~
background-position: 80px 20px;
~~~
那么圖片的左上角會被放在距元素左邊?`80px`?上邊?`20px`?的地方。
### 3.6.6 背景尺寸
`background-size`?是 CSS3 新增的屬性,但卻的到了瀏覽器很好的支持,這個屬性用來控制背景圖片的尺寸,可以給它設定的值及含義如下:
* `50%`:縮放圖片,使其填充背景區的一半。
* `100px`?`50px`:把圖片調整到?`100px`?寬,`50px`?高。
* `cover`:拉大圖片,使其完全填滿背景區,并保持寬高比例。
* `contain`:縮放圖片,使其恰好適應整個背景區域,并保持寬高比例。
### 3.6.7 背景粘附
`background-attachment`?屬性控制滾動元素內的背景圖片是否隨元素滾動而移動,這個屬性默認是?`scroll`,即背景圖片隨元素移動,如果把它的值改為?`fixed`,那么背景圖片不會隨元素滾動而移動。
### 3.6.8 簡寫背景屬性
~~~
background:
[background-color]
[background-image]
[background-repeat]
[background-attachment]
[background-position] / [ background-size]
[background-origin]
[background-clip];
~~~
聲明中少些了哪個屬性(比如沒寫?`no-repeat`),就會使用相應屬性的默認值(`repeat`)。
### 3.6.9 其他 CSS3 背景屬性
CSS3 新增的一些背景屬性:
* `background-clip`:控制背景繪制區域的范圍,比如可以讓背景顏色和背景圖片只出現在內容區,而不出現在內邊距區域,默認情況下背景繪制區域是擴展到邊框外邊界的。
* `background-origin`:控制背景定位區域的原點,可以設定為元素盒子左上角以外的位置。
* `background-break`:控制分離元素(比如跨越多行的行內元素盒子)的顯示效果。
`background-size`、?`background-clip`?和?`background-origin`?的瀏覽器支持情況還是挺不錯的:

### 3.6.10 多背景圖片
CSS3 還可以給元素背景條件多個背景圖片:
~~~
p {
background-image: url(img/1.png),
url(img/2.png),
url(img/3.png);
background-position:20% 20%,
30px 50px,
center center;
background-repeat: repeat,
no-repeat,
repeat;
}
~~~
在 CSS 中,我們把每張圖片的聲明都單獨放在了一行,以逗號分隔,以便看清他們的位置、重復的設定值等等。要注意的是,代碼中先列出的圖片顯示在上方,或者說更接近前景,還有就是對每張背景圖設置重復或者位置的時候,也要用逗號一一對應隔開。
### 3.6.11 背景漸變
漸變就是在一定長度內兩種或多種顏色之間自然過度。漸變分兩種,一種是線性漸變,一種是徑向漸變。線性漸變是從元素的一端延伸到另一端,徑向漸變則是從元素的一點向四周發散,下面來看一個簡單的線性漸變例子:
~~~
// HTML
<div class="gradient effect-1"></div>
<div class="gradient effect-2"></div>
<div class="gradient effect-3"></div>
// CSS
.gradient {
width: 200px;
height: 200px;
margin: 0 20px;
}
/* 默認為從上到下 */
.effect-1 {
background: -webkit-linear-gradient(#45b29a, #fff);
background: -moz-linear-gradient(#45b29a, #fff);
background: -o-linear-gradient(#45b29a, #fff);
background: linear-gradient(#45b29a, #fff);
}
.effect-2 {
background: -webkit-linear-gradient(left, #45b29a, #fff);
background: -moz-linear-gradient(left, #45b29a, #fff);
background: -o-linear-gradient(left, #45b29a, #fff);
background: linear-gradient(to right, #45b29a, #fff);
}
.effect-3 {
background: -webkit-linear-gradient(45deg, #45b29a, #fff);
background: -moz-linear-gradient(45deg, #45b29a, #fff);
background: -o-linear-gradient(45deg, #45b29a, #fff);
background: linear-gradient(45deg, #45b29a, #fff);
}
~~~

上面展示了三種簡單的漸變效果,默認情況下漸變方向是從上到下的如圖一,例 2 起點關鍵字?`left`?意思是漸變方向從左到右,例 3 中的?`45deg`?(順時鐘旋轉 45 度)相當于把起點從默認的中上設定到了又上。
#### 3.6.11.1 漸變點
漸變點就是漸變方向上的點,可以在這些點上設定顏色和不透明度。可以添加任意多個漸變點:
~~~
// HTML
<div class="gradient effect-1"></div>
<div class="gradient effect-2"></div>
<div class="gradient effect-3"></div>
<div class="gradient effect-4"></div>
// CSS
.gradient {
width: 200px;
height: 200px;
margin: 0 20px;
}
/* 50% 處有一個漸變點 */
.effect-1 {
background: -webkit-linear-gradient(#45b29a, #fff 50%, #45b29a);
background: -moz-linear-gradient(#45b29a, #fff 50%, #45b29a);
background: -o-linear-gradient(#45b29a, #fff 50%, #45b29a);
background: linear-gradient(#45b29a, #fff 50%, #45b29a);
}
/* 20% 和 80%處有一個漸變點 */
.effect-2 {
background: -webkit-linear-gradient(#45b29a 20%, #fff 50%, #45b29a 80%);
background: -moz-linear-gradient(#45b29a 20%, #fff 50%, #45b29a 80%);
background: -o-linear-gradient(#45b29a 20%, #fff 50%, #45b29a 80%);
background: linear-gradient(#45b29a 20%, #fff 50%, #45b29a 80%);
}
/* 25%、50% 和 75% 處有一個漸變點 */
.effect-3 {
background: -webkit-linear-gradient(#45b29a, #fff 25%, #45b29a 50%, #fff 75%, #45b29a);
background: -moz-linear-gradient(#45b29a, #fff 25%, #45b29a 50%, #fff 75%, #45b29a);
background: -o-linear-gradient(#45b29a, #fff 25%, #45b29a 50%, #fff 75%, #45b29a);
background: linear-gradient(#45b29a, #fff 25%, #45b29a 50%, #fff 75%, #45b29a);
}
/* 為同一個漸變點設定兩種顏色可以的到突變的效果 */
.effect-4 {
background: -webkit-linear-gradient(#45b29a, #fff 25%, #45b29a 25%%, #45b29a 75%, #fff 75%, #45b29a);
background: -moz-linear-gradient(#45b29a, #fff 25%, #45b29a 25%%, #45b29a 75%, #fff 75%, #45b29a);
background: -o-linear-gradient(#45b29a, #fff 25%, #45b29a 25%%, #45b29a 75%, #fff 75%, #45b29a);
background: linear-gradient(#45b29a, #fff 25%, #45b29a 25%%, #45b29a 75%, #fff 75%, #45b29a);
}
~~~

例 1,如果不是使用百分比或其他值聲明漸變點的位置,三種顏色會均勻分布于整個漸變。
例 2,演示了起點和終點不是 0% 和 100% 時的情形。此時,在第一個漸變點(20%)之前,是第一個漸變點聲明的實色,而在該點之后,則是從該顏色到下一個漸變點顏色的過度。同樣,在最后一個漸變點(80%)之后,該漸變點的顏色會以實色擴展到元素結束。
例 3,簡單展示了相同顏色在幾個漸變點之間變來變去的效果。
例 4,展示了在同一個漸變點聲明兩種不同顏色,能實現一種突變的效果。
#### 3.6.11.2 徑向漸變
在創建徑向漸變的時候,可以使用參數指定形狀、位置、尺寸、顏色和不透明度:
~~~
// HTML
<div class="gradient effect-1"></div>
<div class="gradient effect-2"></div>
<div class="gradient effect-3"></div>
// CSS
.gradient {
width: 300px;
height: 200px;
margin: 0 20px;
}
.effect-1 {
background: -webkit-radial-gradient(#fff, #45b29a);
background: -moz-radial-gradient(#fff, #45b29a);
background: -o-radial-gradient(#fff, #45b29a);
background: radial-gradient(#fff, #45b29a);
}
.effect-2 {
background: -webkit-radial-gradient(circle, #fff, #45b29a);
background: -moz-radial-gradient(circle, #fff, #45b29a);
background: -o-radial-gradient(circle, #fff, #45b29a);
background: radial-gradient(circle, #fff, #45b29a);
}
.effect-3 {
background: -webkit-radial-gradient(50px 30px, circle, #fff, #45b29a);
background: -moz-radial-gradient(50px 30px, circle, #fff, #45b29a);
background: -o-radial-gradient(50px 30px, circle, #fff, #45b29a);
background: radial-gradient(50px 30px, circle, #fff, #45b29a);
}
~~~

例 1,展示了默認的漸變形狀,即漸變效果會填充元素,這里是矩形,如果元素是正方形,那漸變就是圓形:

例 2,設定了關鍵字?`circle`,于是漸變形狀變得均勻,并在元素最近的邊達到終點,形成了圓形漸變。而長邊剩下的區域則填充了終點的顏色。
例 3,位置參數?`50px 30px`?把漸變的圓心放到了靠近左上角的位置。
## 總結
本章的內容不少,都是一些很重要的概念,比如盒模型、定位元素、浮動與清除浮動和元素背景屬性。
到目前為止,也對 《CSS 設計指南》 的重點知識進行了總結,當然可能有些地方總結的不夠好,如有不對的地方歡迎指出和討論。