CSS实现三栏布局的方法

学习一下三栏布局,同时补充一下BFC和文档流的知识。

补充知识:BFC、文档流

BFC叫做块级格式化上下文,是Web页面的可视CSS的一块渲染区域,它决定了块级元素如何对它的子元素内容进行布局,以及决定了与子元素同级别的兄弟元素之间的关系和作用。

根元素,浮动元素,绝对定位元素,行内块元素,flex,grid,overflow不可见的元素等,都会创建格式化上下文,但其实不止这些,还有很多不常见的,比如表格相关,参考mdn。

BFC对浮动的影响很重要,浮动设定和清除只会应用于同一BFC的元素,浮动不会影响其它BFC中元素的布局,清除浮动只能清除同一BFC中在它前面的元素的浮动。BFC可以阻止元素被浮动元素覆盖掉,特就是使用float脱离文档流时,其他盒子会无视这个元素,但其他盒子内的文本依然会为这个元素让出位置,环绕在周围,此时可以使用overflow: hidden取消这个效果。

还有一种很特殊的性质叫做外边距塌陷(有的地方叫外边距折叠,都是一个意思),在同一个BFC下,外边距会发生重叠。比如有两个div在同一个BFC下,给它们设置margin为10px,但两个盒子之间的距离却是10px而不是20px。

文档流是一种用于输出HTML元素的流,从上到下从左到右依次排布布局。但如果使用浮动或某些定位(absolute,fixed)时,元素会脱离文档流,这同时会影响它之后的HTML元素的排布,这就是为什么需要清除浮动。

浮动型三栏布局

采用float方式的布局,左右模块各自向左右浮动,并设置中间模块的 margin 值使中间模块宽度自适应。

但这种方式有一种问题,其main元素必须写在left和right之后,否则浮动将跑到main的下一行。这会导致主要内容的加载优先级比侧边低,在内容较多时,这种方式体验不好。

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>三栏布局</title>
<style>
.container div {
/* 整个栏目的高度 */
height: 200px;
}

.left {
/* 左部分侧边定为左浮动 */
float: left;
width: 300px;
background-color: red;
}

.right {
/* 右部分侧边定为右浮动 */
float: right;
width: 300px;
background-color: red;
}

.main {
/* 左外距大小与左边长度对应,也可以稍大一些做留白,右边同理 */
/* 这里设置两者相等,其实就是一种居中效果,想想margin: 0 auto? */
margin-left: 300px;
margin-right: 300px;
background-color: blue;
}

.main::after {
/* 使用伪元素在main后面加一个清除浮动,这种写法比较优雅 */
content: '';
display: block;
clear: both;
}
</style>
</head>
<body>
<div class="container">
<div class="left"></div>
<div class="right"></div>
<div class="main"></div>
</div>
</body>
</html>

效果:

image-20210919184253594

圣杯布局

圣杯布局是一个很经典的布局,它可以做到首先渲染主体div。

做法:

  • 左中右div设置左浮动,脱离文档流,设定定位方式为相对,设定文字换行

  • 外层容器设置overflow: hidden,触发形成BFC区域条件,撑开整个盒子

  • 左div、右div设置好给定的宽度,这个条件是已知的

  • main盒子设置宽度为100%

  • 左div设置left为负左宽度,左外距为-100%

  • 右div设置right为负右宽度,左外距为负右宽度

  • 外层容器设置右内距为右宽,左内距为左宽

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>
<meta charset="utf-8">
<title>三栏布局</title>
<style>
/* 如果你对这些注释里任何一句话有疑问或者看不懂,自己随便删几条CSS跑跑就知道了 */

.main, .left, .right {
float: left;
position: relative;
height: 300px;
/* 加入这个是为了让文字固定在中间的显示区域中 */
word-break: break-all;
}

.container {
/* 其实这里经过测试,发现不用overflow生成BFC也可以触发,不知道什么原因 */
overflow: hidden;
/* 加入padding是为了将main盒子的两边留白,腾出放置左盒子和右盒子的区域 */
/* 为什么要这么做?如果不这么做,main盒子的内容就会溢出到左右盒子的区域 */
/* 为什么限制main盒子的CSS要放在container里?布局需要 */
padding: 0 300px 0 200px;
}

.left {
width: 200px;
/* left和margin-left共同起一个作用,即,把左盒子原本应该存在的位置向上移动一行 */
left: -200px;
margin-left: -100%;
background: pink;
}

.right {
width: 300px;
/* 与left类似,把右盒子向上移动一行,并放在最右边 */
right: -300px;
margin-left: -300px;
background: pink;
}

.main {
width: 100%;
background: forestgreen;
}
</style>
</head>
<body>
<div class="container">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>

image-20210920224958561

双飞翼布局

双飞翼布局是圣杯布局的变式,两者很类似,只是圣杯布局是用内边距控制盒子大小,双飞翼布局用两层盒子嵌套后通过外边距控制,两边盒子的浮动处理操作还是差不太多的,只不过双飞翼布局不需要使用相对定位。

当然,这份代码里就没有container这个外部容器了,实际写的时候应该要有,而且加上overflow: hidden来生成一个BFC。

做法:

  • 左、中外层、右div设置左浮动,脱离文档流
  • 左盒子和右盒子设定宽度
  • 左盒子设定左外距为负100%,右盒子设定左外距为负宽度
  • 中内层盒子设定左外距为左盒子宽度,右边同理
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>三栏布局</title>
<style>
/* 如果你对这些注释里任何一句话有疑问或者看不懂,自己随便删几条CSS跑跑就知道了 */
.main, .left, .right {
height: 200px;
}

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

.content {
width: 100%;
}

.main {
/* 双飞翼布局的关键就在于是使用外边距进行缩小中间盒子的,左外距和右外距与分别与两侧边等宽 */
margin-left: 200px;
margin-right: 300px;
background-color: indigo;
}

.left {
width: 200px;
/* 在浮动下,让左侧边盒子向上移动一行 */
margin-left: -100%;
background-color: royalblue;
}

.right {
width: 300px;
/* 在浮动下,让右边盒子向上移动一行 */
margin-left: -300px;
background-color: royalblue;
}
</style>
</head>
<body>
<!-- HTML结构有较大变化 -->
<div class="content">
<div class="main"></div>
</div>
<div class="left"></div>
<div class="right"></div>
</body>
</html>

image-20210920230848633

绝对定位布局

一种也算比较实用的布局方式,这种写法比较直观,也就是用子盒子相对父盒子进行绝对定位,并对齐。

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>三栏布局</title>
<style>
.container {
/* 放置一个相对定位对它本身没有什么用,但是可以用来给子元素绝对定位作为父级元素参照 */
/* absolute元素相对于最近的非static定位祖先元素的偏移,来确定元素位置 */
/* 不写也行,我试过,但盒子对不齐,定位不好调,不如这样写省事 */
position: relative;
}

.main, .left, .right {
height: 300px;
}

.main {
margin: 0 200px;
background-color: orangered;
}

.left {
position: absolute;
width: 200px;
/* 这里的left和top是相对container定位的,用于对齐盒子,下面的同理 */
left: 0;
top: 0;
background-color: limegreen;
}

.right {
position: absolute;
width: 200px;
background-color: limegreen;
right: 0;
top: 0;
}
</style>
</head>
<body>
<div class="container">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>

flex布局

flex做三栏布局可能是最简单的,直观,且实用。

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>三栏布局</title>
<style>
/* flex做三栏布局可能是最简单的 */
.container {
display: flex;
}

.container div {
height: 200px;
}

.left {
/* 使用order是为了改变元素摆放顺序,这样不需要将left排在main之前,可以优先渲染main */
order: -1;
width: 200px;
background: coral;
}

.right {
width: 400px;
background: coral;
}

.main {
/* 一般情况下可能会直接用flex: 1,但第三个参数代表的flex-basis可以用来设定中间盒子的最小宽度 */
flex: 1 1 800px;
background: seagreen;
}
</style>
</head>
<body>
<div class="container">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>

image-20210920232110609

其实能用的布局方案远不止这些,但其他的应该算不常见或者现在已经不常用了吧。

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2018-2023 Shawn Zhou
  • Hexo 框架强力驱动 | 主题 - Ayer
  • 访问人数: | 浏览次数:

感谢打赏~

支付宝
微信