在我之前的博客網頁整體布局完全剖析—剖完你不進來看一下么?中總結單列、兩列、三列固寬與變寬布局,我還以為已經囊括了所有經典的網頁布局方法了呢,當然除了CSS3的彈性盒模型沒有涉及到,現在看來確實是自己孤陋寡聞了,以前在看資料的時候無意中看過聖杯布局和雙飛翼布局這樣的名詞,只不過當時基礎是在太差直接忽略了(當然現在也是在打基礎,但是好歹相對幾個月前已經有了質的改變)。今天總結時再次看到這兩個布局方法,當然再也不能錯過了。
聖杯布局與雙飛翼布局針對的都是三列左右欄固定中間欄邊框自適應的網頁布局(想象一下聖杯是主體是加上兩個耳朵;鳥兒是身體加上一對翅膀),聖杯布局是Kevin Cornell在2006年提出的一個布局模型概念,在國內最早是由淘寶UED的工程師(傳說是玉伯)改進並傳播開來,在中國也有叫法是雙飛翼布局,它的布局要求有幾點:
三列布局,中間寬度自適應,兩邊定寬;
中間欄要在瀏覽器中優先展示渲染;
允許任意列的高度最高;
下面我們看看具體的實現方法。
一、聖杯布局

HTML結構
|
1
2
3
4
5
6
7
|
<
div
class
=
"header"
>header</
div
>
<
div
class
=
"container"
>
<
div
class
=
"main"
>main</
div
>
<
div
class
=
"left"
>left</
div
>
<
div
class
=
"right"
>right</
div
>
</
div
>
<
div
class
=
"footer"
>footer</
div
>
|
因為需要中間欄優先展示渲染,所以中間的main在HTML的結構中卻是最靠前的。在實際的網站中這樣做的好處就是用戶能夠先看到網頁正文信息,一般網頁兩邊的導航信息和說明信息我們認為優先級沒有正文重要。
1.設置一下基本樣式
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
*{
margin
:
0
;
padding
:
0
;}
body{
min-width
:
700px
;}
.header,.footer{
border
:
1px
solid
#333
;
background
:
#aaa
;
text-align
:
center
;
}
.
left
,.main,.
right
{
min-height
:
130px
;
}
.container{
border
:
2px
solid
yellow;
}
.
left
{
width
:
200px
;
background
:
red
;
}
.
right
{
width
:
220px
;
background
:
green
;
}
.main{
background
:
blue
;
}
|
為了高度保持一致給left middle right都加上min-height:130px

2.將主體部分的三個子元素都設置左浮動
|
1
2
3
|
.
left
,.main,.
right
{
float
:
left
;
}
|
此時的頁面顯示如圖所示,Shen Me Gui沒關系,事情會變得好起來的

我們看一下上面的效果比較明顯的兩個問題,一是footer跑到上面去了,二是container容器高度塌陷了,這是典型的“清除浮動和閉合浮動”問題。
3.解決浮動問題
|
1
2
3
4
5
6
7
|
.container{
border
:
2px
solid
yellow;
overflow
:
hidden
;
}
.footer{
clear
:
both
;
}
|
給container加上overflow:hidden觸發BFC閉合浮動,給footer加上clear屬性清除浮動。

我們發現footer移到了下面,並且container的高度塌陷也修復了。
4.設置main寬度為width:100%,讓其單獨占滿一行
|
1
2
3
4
|
.main{
width
:
100%
;
background
:
blue
;
}
|

5.設置left和right負的外邊距
我們的目標是讓left、main、right依次並排,但是上圖中left和right都是位於下一行,這里的技巧就是使用負的margin-left:
|
1
2
3
4
5
6
7
8
9
10
|
.
left
{
margin-left
:
-100%
;
width
:
200px
;
background
:
red
;
}
.
right
{
margin-left
:
-220px
;
width
:
220px
;
background
:
green
;
}
|
負的margin-left會讓元素沿文檔流向左移動,如果負的數值比較大就會一直移動到上一行。關於負的margin的應用也是博大精深,這里肯定是不能詳細介紹了。
設置left部分的margin-left為-100%,就會使left向左移動一整個行的寬度,由於left左邊是父元素的邊框,所以left繼續跳到上一行左移,一直移動到上一行的開頭,並覆蓋了main部分(仔細觀察下圖,你會發現main里面的字“main”不見了,因為被left遮住了),left上移過后,right就會處於上一行的開頭位置,這是再設置right部分margin-left為負的寬度,right就會左移到上一行的末尾。

6.修復覆蓋問題
第五步我們說過設置left和right負的外邊距覆蓋了main部分的內容,現在想辦法修復這個問題,首先給container的左右加上一個內邊距,分別為left和right的寬度。
|
1
2
3
4
5
|
.container{
border
:
2px
solid
yellow;
padding
:
0
220px
0
200px
;
overflow
:
hidden
;
}
|

由於left、main、right三個部分都被container包裹着,所以給其添加內邊距,三個子元素會往中間擠。貌似還是沒有修復問題,別着急,我們已經在container的左右兩邊留下了相應寬度的留白,只要把left和right分別移動到這兩個留白就可以了。可以使用相對定位移動left和right部分,
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
.
left
,.main,.
right
{
position
:
relative
;
float
:
left
;
min-height
:
130px
;
}
.
left
{
margin-left
:
-100%
;
left
:
-200px
;
width
:
200px
;
background
:
red
;
}
.
right
{
margin-left
:
-220px
;
right
:
-220px
;
width
:
220px
;
background
:
green
;
}
|

至此,我們完成了三列中間自適應的布局,也就是傳說中的聖杯布局。完整的代碼如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
<!DOCTYPE html>
<
html
>
<
head
>
<
meta
charset
=
"utf-8"
>
<
title
>聖杯布局</
title
>
<
style
type
=
"text/css"
>
*{margin: 0;padding: 0;}
body{min-width: 700px;}
.header,
.footer{
border: 1px solid #333;
background: #aaa;
text-align: center;
}
.left,
.main,
.right{
position: relative;
float: left;
min-height: 130px;
}
.container{
border: 2px solid yellow;
padding:0 220px 0 200px;
overflow: hidden;
}
.left{
margin-left: -100%;
left: -200px;
width: 200px;
background: red;
}
.right{
margin-left: -220px;
right: -220px;
width: 220px;
background: green;
}
.main{
width: 100%;
background: blue;
}
.footer{
clear: both;
}
</
style
>
</
head
>
<
body
>
<
div
class
=
"header"
>header</
div
>
<
div
class
=
"container"
>
<
div
class
=
"main"
>main</
div
>
<
div
class
=
"left"
>left</
div
>
<
div
class
=
"right"
>right</
div
>
</
div
>
<
div
class
=
"footer"
>footer</
div
>
</
body
>
</
html
>
|
二、雙飛翼布局

聖杯布局和雙飛翼布局解決問題的方案在前一半是相同的,也就是三欄全部float浮動,但左右兩欄加上負margin讓其跟中間欄div並排,以形成三欄布局。不同在於解決”中間欄div內容不被遮擋“問題的思路不一樣。
HTML 結構
|
1
2
3
4
5
6
7
8
9
|
<
div
class
=
"header"
>header</
div
>
<
div
class
=
"container"
>
<
div
class
=
"main"
>
<
div
class
=
"content"
>main</
div
>
</
div
>
<
div
class
=
"left"
>left</
div
>
<
div
class
=
"right"
>right</
div
>
</
div
>
<
div
class
=
"footer"
>footer</
div
>
|
雙飛翼布局的前五步和聖杯布局完全相同,我們只需要修改第六步,前面是設置container的內邊距以及相對定位來解決這個覆蓋問題的,雙飛翼布局中,為了main內容不被遮擋,在main里面添加一個子元素content來顯示內容,然后設置content的margin-left和margin-right為左右兩欄div留出位置。

直接貼出代碼,讀者可以自行參透他們的異同:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
<!DOCTYPE html>
<
html
>
<
head
>
<
meta
charset
=
"utf-8"
>
<
title
>聖杯布局</
title
>
<
style
type
=
"text/css"
>
*{margin: 0;padding: 0;}
body{min-width: 700px;}
.header,
.footer{
border: 1px solid #333;
background: #aaa;
text-align: center;
}
.left,
.main,
.right{
float: left;
min-height: 130px;
}
.container{
border: 2px solid yellow;
overflow: hidden;
}
.left{
margin-left: -100%;
width: 200px;
background: red;
}
.right{
margin-left: -220px;
width: 220px;
background: green;
}
.main{
width: 100%;
background: blue;
}
.content{
margin: 0 220px 0 200px;
}
.footer{
clear: both;
}
</
style
>
</
head
>
<
body
>
<
div
class
=
"header"
>header</
div
>
<
div
class
=
"container"
>
<
div
class
=
"main"
>
<
div
class
=
"content"
>main</
div
>
</
div
>
<
div
class
=
"left"
>left</
div
>
<
div
class
=
"right"
>right</
div
>
</
div
>
<
div
class
=
"footer"
>footer</
div
>
</
body
>
</
html
>
|
雙飛翼布局比聖杯布局多使用了1個div,少用大致4個css屬性(聖杯布局container的 padding-left和padding-right這2個屬性,加上左右兩個div用相對布局position: relative及對應的right和left共4個屬性,;而雙飛翼布局子div里用margin-left和margin-right共2個屬性,比聖杯布局思路更直接和簡潔一點。簡單說起來就是”雙飛翼布局比聖杯布局多創建了一個div,但不用相對布局了。
參考
