圣杯&双飞翼布局

圣杯、双飞翼布局是三列布局中的两个经典布局,特点是加载页面时先加载中间主列的内容。其中双飞翼布局始于淘宝UED。

在掌握这两个布局前,首先要知道什么是负边距。

margin 负边距

负边距的使用有两种场景。

在static元素中使用负边距

图片来源于sifou

一个static元素是一个没有使用过float的元素。上面的图片展示了一个static的元素使用负边距之后的情况。

  • 当一个static元素在top/left使用负边距时,它把元素向这个特定的方向拉。
  • 但是当你将负边距设置为相对bottom/right时,它并不会把元素向下或右拉,相反,它会把后面的元素往里面拉,从而覆盖自己。
  • 如果宽度没有设置,左右负边距会把元素向两个方向拉以增加宽度。在这里margin的作用相当于padding

用下面这段代码进行实验:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div{
margin: 0;
}
#mydiv1{
width: 200px;
height: 200px;
background-color: hotpink;
}
#mydiv2{
width: 200px;
height: 200px;
background-color: deepskyblue;
}
</style>
</head>
<body>
<div id="mydiv1"></div>
<div id="mydiv2"></div>
</body>
</html>

我们先为 mydiv1 加上一个left的负边距

1
#mydiv1{margin-left:-100px;}

可以看到 mydiv1 向左“移动”了100px,同时 margin-left 显示的确为-100px。

为 mydiv1 加上一个bottom的负边距

1
#mydiv1{margin-bottom:-100px;}

现在 mydiv2 被 mydiv2 向上“拖”了100px,margin-bottom也有对应的显示。

在浮动中使用负边距

  • 如果对一个浮动的元素使用负边距,它会产生一个空白,其他元素就可以覆盖这一部分。
  • 如果两个元素都使用了左浮动并且设置margin-right:-20px。#mydiv2会把#mydiv1看成宽度缩小20px(所以会覆盖一部分),但是有趣的是#mydiv1并不会有任何变化,而是依然保持原先的宽度。

圣杯&双飞翼的共同处

这两个布局是一种三列布局,随着页面的宽度的变化,这三列布局总是中间盒子优先渲染,两边的盒子宽度固定不变,即使页面宽度变小,也不影响我们的浏览。

既然要满足中间盒子优先渲染,就要把中间盒子的代码写在左右两列之前:

1
2
3
4
5
<div class="box">
<div class="main">我是C位</div>
<div class="left">我是小左</div>
<div class="right">我是小右</div>
</div>

先加上基本的css样式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.main{
float: left;
width: 100%;
height: 400px;
background-color: hotpink;
}
.left{
float: left;
width: 200px;
height: 400px;
background-color: deepskyblue;
}
.right{
float: left;
width: 200px;
height: 400px;
background-color: yellowgreen;
}

所有盒子都成功的渲染出来了,中间盒子优先渲染,而且左右两列宽度固定不变,主列也会随着浏览器宽度的变化而变化。但是左右两列,却跑远了。

这时我们就要使用负边距把左右给拉回来。

添加代码:

1
2
.left{margin-left: -100%}
.right{margin-left: -200px;}

因为C位的宽度是 100% ,让小左左移 100% 即可到C位的最左边。同理让小右上去,只要平移一个自身的宽度 200px 就可以了。

这时可能会有个疑问,C位和小左不是不在一列的吗?左移怎么会移动到上一列呢?

因为在设置浮动后,元素就已经脱离文档流了。可以想象此时的盒子都是在一列上往左边挤,不过由于第一个盒子太宽,才把后边的盒子挤下去了。

Nice! 三列布局就这样要完成了。

为什么说只是要完成?我们发现中间盒子的字被遮不见了。其实现在中间盒子的宽度没有变,还是 100% 。只是左右列压了上去,造成了这样的效果。

要让中间盒子的内容重见天日,圣杯&双飞翼采用了不同的方法。

双飞翼布局

既然要看到字,那就把字平移回来。双飞翼布局在C位的内容区新加了一个 div ,再把这个 div 向右平移。

于是html就变成了这样:

1
2
3
4
5
6
7
<div class="root">
<div class="main">
<div class="main-inner">我是C位</div>
</div>
<div class="left">我是小左</div>
<div class="right">我是小右</div>
</div>

然后在 CSS 中新增样式:

1
.main-inner{margin-left: 200px;}

将 main-inner 右移一个左边框的宽度。

圣杯布局

与双飞翼相反,圣杯布局是把两个边框向外移。再外移之前先要把.root往里收一个左右边框的距离,然后再移动。

在 CSS 中新增.root样式:

1
2
3
4
.root{
margin-left: 200px;
margin-right: 200px;
}

让.root左右的的外边距增加 200px 。

然后在 CSS 中新增左右盒子的样式样式:

1
2
3
4
5
6
7
8
.left{
position: relative;
left: -200px;
}
.right{
position: relative;
right: -200px;
}

达到了同样的效果。

结语

双飞翼相比于圣杯,多了1个div,少用大致4个css属性。圣杯布局则是完全在CSS上做文章,保留了基本的文档结构。

两种布局各有特色,但个人比较喜欢圣杯布局。