0%

三栏式布局

以前常听说圣杯布局和双飞翼布局,并没有认真研究过,但实际上,他们只是三栏式布局的两种布局方法而已。本文将介绍三栏式布局的几种思路。

初级方法

页面布局常常要用到左右固定,中间自适应的三栏式布局,以前使用的是下面两种方法:

  • 方法一:左右设置固定宽度,然后使用绝对定位position:absolute及left、right属性定位左右盒子位置,最后根据左右宽度设置中间部分的margin。

    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
    .container {
    height:200px;
    overflow:hidden;
    }
    .left {
    width: 200px;
    height: 200px;
    position: absolute;
    left: 0;
    top: 40px;
    background-color: #E79F6D;
    }
    .middle {
    height: 200px;
    margin: 0 210px 0 200px;
    background-color: #D6D6D6;

    .right {
    width: 210px;
    height: 200px;
    position: absolute;
    right: 0;
    top: 40px;
    background-color: #77BBDD;
    }
  • 方法二:左右设置固定宽度,分别左右浮动;根据左右宽设置中间部分的margin;设置父元素overflow:hidden;注意采用这种方法时,html布局上中间部分必须放在最后,即左右中的顺序,这是因为中间不是浮动的,需要单独占行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    .container {
    height:200px;
    overflow:hidden;
    }
    .left {
    width: 200px;
    height: 200px;
    float: left;
    background-color: #E79F6D;
    }
    .right {
    width: 210px;
    height: 200px;
    float: right;
    background-color: #77BBDD;
    }
    .middle {
    height: 200px;
    margin: 0 210px 0 200px;
    background-color: #D6D6D6;
    }

但是,实际产品中往往需要中间部分最先渲染,也就是“重要的内容先加载”,这种结构会更好一些,所以我们需要中左右的布局顺序,这种情况有两种经典的实现方式:圣杯布局和双飞翼布局。

圣杯布局

下面我们按照常规思路来一步步实现圣杯布局:
原始布局
HTML结构:

1
2
3
4
5
6
7
<header>Header</header>
<div class="container">
<div class="middle">中间弹性区</div>
<div class="left">左边栏</div>
<div class="right">右边栏</div>
</div>
<footer>Footer</footer>

每个盒子的样式:

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
header {
width: 100%;
height: 40px;
background-color: #aaa;
}
.container {
overflow:hidden;
}
.middle {
width: 100%;
height: 200px;
float:left;
background-color: #D6D6D6;
}
.left {
width: 200px;
height: 200px;
float:left;
background-color: #E79F6D;
}
.right {
width: 210px;
height: 200px;
float:left;
background-color: #77BBDD;
}
footer {
width: 100%;
height: 30px;
clear: both;
background-color: #666;
}

问题:此时三栏并没有在父元素的一行显示,因为中间盒子我们给了百分之百的宽度,所以左右两个盒会被挤下来。

  1. 这时需要让左右两边的盒子上去,可以通过负边距实现。
    设置左边盒子的左边距为负的container的宽度,即.left {margin-left:-100%;}
    设置右边的盒子其左边距为负的自己的宽度,也就是.right {margin-left:-200px;}
    问题:此时中间盒子里的内容会被左右盒子给压住一部分。

  2. 利用父级元素设置左右内边距的值,把父级的盒子往中间挤。.container{ padding: 0 200px 0 200px;}
    问题:左右盒子都随中间盒子往中间挤了,需要将左右的恢复到原来的位置。

  3. 给左右两个盒子加相对定位,左右两个盒子就可以设置left和right值。.left{ position: relative; left: -200px;},.right{position: relative;right: -210px;}。至此,圣杯布局完成。

缺点:并没有实现等高布局;使用了相对定位,扩展性不好。

完整代码如下:

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
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
header {
width: 100%;
height: 40px;
background-color: #aaa;
}
.container {
height:200px;
padding: 0 210px 0 200px;
overflow:hidden;
}
.middle {
width: 100%;
height: 200px;
float:left;
background-color: #D6D6D6;
}
.left {
width: 200px;
height: 200px;
margin-left:-100%;
float:left;
position: relative;
left: -200px;
background-color: #E79F6D;
}
.right {
width: 210px;
height: 200px;
margin-left: -210px;
float:left;
position: relative;
right: -210px;
background-color: #77BBDD;
}
footer {
width: 100%;
height: 30px;
background-color: #666;
}
</style>
</head>
<body>
<header>Header</header>
<div class="container">
<div class="middle">中间弹性区</div>
<div class="left">左边栏</div>
<div class="right">右边栏</div>
</div>
<footer>Footer</footer>
</body>
</html>

双飞翼布局

双飞翼布局可以看成是对圣杯布局的改进。前两步都是一样的,重要的是第三步,在前两步的完成后已经形成同行排列,只不过中间栏里面的内容被遮挡。为解决这个问题,圣杯布局的第三步是给container容器添加padding属性,而双飞翼布局是为main里面的内容再加一个div,让main的内容包含在内层div里,设置内层div的margin-left和margin-right为左右两栏div留出位置。

优点:比圣杯布局少用了多个属性,更直接和简洁。
缺点:并没有实现等高布局,增加了html结构。

1
2
3
4
5
6
7
8
9
<header>Header</header>
<div class="container">
<div class="middle">
<div class="middle-inner">中间弹性区</div>
</div>
<div class="left">左边栏</div>
<div class="right">右边栏</div>
</div>
<footer>Footer</footer>
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
header {
width: 100%;
height: 40px;
background-color: #aaa;
}
.container {
height:200px;
overflow:hidden;
}
.middle {
width: 100%;
height: 200px;
float:left;
background-color: #D6D6D6;
}
.left {
width: 200px;
height: 200px;
margin-left:-100%;
float:left;
background-color: #E79F6D;
}
.right {
width: 210px;
height: 200px;
margin-left: -210px;
float:left;
background-color: #77BBDD;
}
.middle-inner {
margin: 0 210px 0 200px;
}
footer {
width: 100%;
height: 30px;
clear: both;
background-color: #666;
}

绝对定位

设置子元素的top:0;bottom:0;使得所有子元素的高度都和父元素的高度相同,实现等高效果。
缺点: 需要为容器元素设置高度,扩展性较差。

1
2
3
4
5
6
7
<header>Header</header>
<div class="container">
<div class="middle">中间弹性区</div>
<div class="left">左边栏</div>
<div class="right">右边栏</div>
</div>
<footer>Footer</footer>
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
   header {
width: 100%;
height: 40px;
background-color: #aaa;
}
.container {
height: 200px;
position: relative;
}
.middle,
.left,
.right {
position: absolute;
top: 0;
bottom: 0;
}
.middle {
left: 200px;
right: 210px;
background-color: #D6D6D6;
}
.left {
width: 200px;
background-color: #E79F6D;
}
.right {
width: 210px;
right: 0;
background-color: #77BBDD;
}
footer {
width: 100%;
height: 30px;
background-color: #666;
}

flex布局

flex中的伸缩项目默认都拉伸为父元素的高度,可实现等高效果。通过改变伸缩项目的order,可以实现元素顺序调换的效果。
设置中间盒子flex: 1可实现伸缩。flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。如果所有项目的flex-grow属性都为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
25
26
27
28
29
30
header {
width: 100%;
height: 40px;
background-color: #aaa;
}
.container {
display: flex;
}
.middle {
order: 1;
flex: 1;
height: 200px;
background-color: #D6D6D6;
}
.left {
width: 200px;
height: 200px;
background-color: #E79F6D;
}
.right {
order: 2;
width: 210px;
height: 200px;
background-color: #77BBDD;
}
footer {
width: 100%;
height: 30px;
background-color: #666;
}

总结

各种方法各有优缺点,个人更倾向于使用强大简洁的flex布局,让古董浏览器见鬼去吧。

后记

最近在找一些小项目练手,在github上看到很多如我一样的初学者,他们将做项目中遇到的每个问题,无论大小,分析根源,记录在博客中,他们认真细致的态度真让我自愧不如,甚至惊叹。现在他们很多是BAT的员工了,我想这是助他们进入大公司的重要特质之一。像我就是很多时候遇到问题,没有及时记录,或者问题没有分析透彻,似懂非懂,结果下次遇到还是不会。深入思考,弄清每一处细节,比似懂非懂多学几个知识点要重要得多。

参考

圣杯布局和双飞翼布局-简书
三栏式布局(所谓的圣杯和双飞翼)-博客园