浅析圣杯布局和双飞翼布局

三列布局是一种很常见的页面布局方式,三列一般分别是子列sub、主列main和附加列extra,其中子列一般是居左的导航,且宽度固定;主列是居中的主要内容,宽度自适应;附加列一般是广告等额外信息,居右且宽度固定。
圣杯布局和双飞翼布局都可以实现这种三列布局,他们有什么特别之处呢?

在分析圣杯布局和双飞翼布局之前,抛砖引玉,先看看我之前是如何实现左右定宽、中间自适应的三列布局的:子列和附加列分别浮动到左边和右边,主列设置左右外边距即可,需要注意的是子列和附加列要写在主列的前面,顺序不能变。

1
2
3
<div class="sub">子列</div>
<div class="extra">附加列</div>
<div class="main">主列</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.sub {
float: left;
width: 200px;
height: 300px;
background-color: rgba(255, 0, 0, .5);
}
.extra {
float: right;
width: 180px;
height: 300px;
background-color: rgba(0, 255, 0, .5);
}
.main {
height: 300px;
margin-left: 210px;
margin-right: 190px;
background-color: rgba(0, 0, 255, .5);
}

圣杯布局

圣杯布局源自 Matthew Levine 在06年的一篇文章,其DOM结构如下:

1
2
3
4
5
<div class="container">
<div class="main"></div>
<div class="sub"></div>
<div class="extra"></div>
</div>

接下来,让我们一步一步地实现圣杯布局;

1、 首先分别浮动main、sub、extra三列, 然后利用负外边距把sub列和extra列定位到左右两边。这时的CSS代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.main {
float: left;
width: 100%;
height: 300px;
background-color: rgba(255, 0, 0, .5);
}
.sub {
float: left;
width: 200px;
height: 300px;
margin-left: -100%;
background-color: rgba(0, 255, 0, .5);
}
.extra {
float: left;
width: 180px;
height: 300px;
margin-left: -180px;
background-color: rgba(0, 0, 255, .5);
}

2、 完成上步后,sub和extra列已经到了正确的位置,但是sub和extra列却覆盖了main的两边,对于这个问题,圣杯布局的解决办法是给容器container添加左、右内边距,从而让main列定位到正确的位置。

1
2
3
4
.container {
padding-left: 210px;
padding-right: 190px;
}

3、 完成第二步后又出现了新问题:sub、extra列也受到容器左右内边距的影响位置发生了移动。为了解决这个问题,圣杯布局使用相对定位使sub、extra列回到正确的位置。新添加代码如下:

1
2
3
4
5
6
7
8
.sub {
position: relative;
left: -210px;
}
.extra {
position: relative;
right: -190px;
}

4、 当浏览器缩小到一定程度时,这个布局可能会被破坏,可以在body上添加min-width属性解决。最终的圣杯布局CSS代码如下:

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
body {
min-width: 600px; /* 2*sub + extra */
}
.container {
padding-left: 210px;
padding-right: 190px;
}
.main {
float: left;
width: 100%;
height: 300px;
background-color: rgba(255, 0, 0, .5);
}
.sub {
position: relative;
left: -210px;
float: left;
width: 200px;
height: 300px;
margin-left: -100%;
background-color: rgba(0, 255, 0, .5);
}
.extra {
position: relative;
right: -190px;
float: left;
width: 180px;
height: 300px;
margin-left: -180px;
background-color: rgba(0, 0, 255, .5);
}

点击查看在线demo

圣杯布局的优点总结如下:

  1. 使主要内容列先加载。
  2. 允许任何列是最高的。
  3. 没有额外的div。
  4. 需要的hack很少。

双飞翼布局

了解了圣杯布局,趁热打铁,再分析一下双飞翼布局是怎么回事。双飞翼布局源自淘宝UED,现在查看下淘宝店铺的DOM结构,就能找到双飞翼布局的身影。接下来,让我们也一步一步实现双飞翼布局。

  1. 首先,和圣杯布局一样,分别浮动main、sub和extra列,然后利用负外边距正确定位sub和extra列。
  2. 这时依旧面临和圣杯布局同样的问题:main列没有正确定位且被sub、extra列覆盖。双飞翼布局的解决办法是在main列外面包裹了一个宽度100%的div,然后通过设置main列的左、右外边距正确定位main列。最终的DOM结构如下:
    1
    2
    3
    4
    5
    <div class="main-wrapper">
    <div class="main"></div>
    </div>
    <div class="sub"></div>
    <div class="extra"></div>

CSS设置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.main-wrapper {
float: left;
width: 100%;
}
.main {
height: 300px;
margin-left: 210px;
margin-right: 190px;
background-color: rgba(255, 0, 0, .5);
}
.sub {
float: left;
width: 200px;
height: 300px;
margin-left: -100%;
background-color: rgba(0, 255, 0, .5);
}
.extra {
float: left;
width: 180px;
height: 300px;
margin-left: -180px;
background-color: rgba(0, 0, 255, .5);
}

点击查看在线demo

双飞翼布局非常灵活,通过调整css代码可以实现各种布局。例如,利用双飞翼布局实现了一套栅格布局系统

双飞翼布局的优点:

  1. DOM按照主、子、附加列的顺序加载,实现了重要内容先加载。
  2. main部分是自适应宽度的,很容易在定宽布局和流体布局中切换。
  3. 在浏览器上的兼容性非常好,IE5.5以上都支持。
  4. 实现了内容与布局的分离,即Eric提到的Any-Order Columns.
  5. 任何一栏都可以是最高栏,不会出问题。
  6. 需要的hack非常少。

圣杯布局与双飞翼布局的比较

总结一下两种布局方式在实现上的异同点:

  1. 俩种布局方式都是把主列放在文档流最前面,使主列优先加载。
  2. 两种布局方式在实现上也有相同之处,都是让三列浮动,然后通过负外边距形成三列布局。
  3. 两种布局方式的不同之处在于如何处理中间主列的位置:圣杯布局是利用父容器的左、右内边距定位;双飞翼布局是把主列嵌套在div后利用主列的左、右外边距定位。

两者相比较,双飞翼布局虽然多了一个div,却减少了相对定位属性的代码,个人认为双飞翼布局在实现思路和代码简洁度上都要比圣杯布局更好一些。