聊聊圣杯布局和双飞翼布局

一、前言

圣杯布局和双飞翼布局这道面试题我看过很多次了,每一次都以为自己看明白了, 结果一段时间不看还是忘记了,可能是我经历的面试层次太低,没有考到吧。。再就是平时开发中一般没有这种优化要求,用的比较少,今天就再次好好看看并总结如下:

二、由来

这部分摘自知乎CSS 圣杯布局和双飞翼布局的理解与思考

圣杯布局来源于文章In Search of the Holy Grail,而双飞翼布局来源于淘宝UED。虽然两者的实现方法略有差异,不过都遵循了以下要点:

  • 两侧宽度固定,中间宽度自适应
  • 中间部分在DOM结构上优先,以便先行渲染
  • 允许三列中的任意一列成为最高列
  • 只需要使用一个额外的<div>标签

三、实现圣杯布局

3.1. 整体思路

整体思路(面试中问道思路可以这样答):

圣杯布局的主要思路是利用左右padding预留出左右两栏的空间, 在通过负margin + 定位将左右两栏调整到预留的空间中

3.2 具体实现

3.2.1 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>圣杯布局</title>
<link rel="stylesheet" href="./css/grail.css">
</head>
<body>
<!-- 为了熟悉语义化标签,这里使用header,和div效果一样 -->
<header>这是标题</header>
<main>
<div class="main">这是内容</div>
<div class="left">这是左侧的</div>
<div class="right">这是右侧</div>
</main>
<footer>这是页脚</footer>
</body>
</html>

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
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
* {
margin: 0;
padding: 0;
text-align: center;
color: #fff;
}

header,
footer {
background-color: #058ED2;
height: 100px;
line-height: 100px;
}

main {
/* 通过左右padding预留出左右两栏的位置 */
padding: 0 300px 0 200px;
position: relative;
}

main::after {
content: "";
display: block;
clear: both;
}

.main,
.left,
.right {
float: left;
}

.main {
height: 400px;
line-height: 400px;
background-color: #ccc;
width: 100%;
}

.left {
height: 200px;
width: 200px;
line-height: 200px;
background-color: #55007f;
margin-left: -100%;
position: relative;
left: -200px;
}

.right {
height: 300px;
width: 300px;
line-height: 300px;
background-color: #55aa7f;
margin-left: -300px;
position: relative;
left: 300px;
}

3.3.2 效果

思考1:为什么要包裹一层main标签?

思考2:圣杯布局在宽度缩小到一定程度时,页面结构会崩塌,这是为什么

四、实现双飞翼布局

4.1 双飞翼布局存在的意义

圣杯布局已经解决了三栏的问题, 为什么淘宝UED还要提出双飞翼布局?具体见上面思考2

4.2 整体思路

双飞翼布局通过主体区域左右margin预留出左右两栏的空间,在通过负margin将两栏移动到预留出的空白实现

4.3 实现

4.3.1 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>双飞翼布局</title>
<link rel="stylesheet" href="./css/wings.css">
</head>
<body>
<!-- 为了熟悉语义化标签,这里使用header,和div效果一样 -->
<header>这是标题</header>
<main>
<div class="main">这是内容</div>
</main>
<div class="left">这是左侧的</div>
<div class="right">这是右侧</div>
<footer>这是页脚</footer>
</body>
</html>

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
* {
margin: 0;
padding: 0;
text-align: center;
color: #fff;
}

header,
footer {
background-color: #058ED2;
height: 100px;
line-height: 100px;
}

main {
width: 100%;
float: left;

}

.left,
.right {
float: left;
}

/* 为main设置外边距,预留左右两侧空间 */
.main {
margin: 0 300px 0 200px;
height: 500px;
line-height: 500px;
background-color: #55557f;
}

.left {
width: 200px;
height: 200px;
background-color: #00ACED;
line-height: 200px;
margin-left: -100%;
}

.right {
height: 400px;
width: 300px;
margin-left: -300px;
background-color: #111111;
line-height: 400px;
}

footer {
clear: both;
}

4.3.2 效果

五、总结

圣杯布局和双飞翼布局各有各的优点和长处,具体还是根据业务需求来选择(脱离业务谈技术选型无异于扯淡)

圣杯布局当页面无限缩放时页面结构会崩塌,且利用margin和定位,代码更复杂,但代码结构更符合语义化规范

双飞翼布局代码不符合语义规范,可读性较差(中间三栏本应该在同级,且三栏的父级应该和头尾同级;而实现时除了主体都属于一级,主体属于子级,具体查看双飞翼布局的dom结构),但是代码更简洁,且不存在崩塌的问题