# CSS多列布局的实现
实际上我们在讨论布局的时候,会把网页上特定的区域进行分列操作。按照分列数目,可以大致分为 3 类,即单列布局、2 列布局、3 列布局等。
# 基本实现思路
要实现 2 列布局或 3 列布局,可以按照下面的步骤来操作:
(1)为了保证主要布局容器优先级,应将主要布局容器写在次要布局容器之前。
(2)将布局容器进行水平排列;
(3)设置宽度,即次要容器宽度固定,主要容器撑满;
(4)消除布局方式的副作用,如浮动造成的高度塌陷;
(5)为了在窄屏下也能正常显示,可以通过媒体查询进行优化。(响应式布局)
# 单列布局
单列布局是最常用的一种布局,它的实现效果就是将一个元素作为布局容器,通常设置一个较小的(最大)宽度来保证不同像素宽度屏幕下显示一致。
# 示例网站
拉勾,蓝色区域为布局容器,水平居中对齐,宽度1260px
:
谷歌搜索,蓝色区域为布局容器,水平左对齐,宽度 652px
:
一些网站会将单列布局与其他布局方式混合使用,比如拉勾网首页的海报和左侧标签就使用了 2 列布局,这样既能向下兼容窄屏幕,又能按照主次关系显示页面内容。
这种布局的优势在于基本上可以适配超过布局容器宽度的各种显示屏幕,比如上面的示例网站布局容器宽度为 700px
,也就是说超过 700px
宽度的显示屏幕上浏览网站看到的效果是一致的。
但它最大的缺点也是源于此,过度的冗余设计必然会带来浪费。例如,在上面的例子中,其实我的屏幕宽度是足够的,可以显示更多的内容,但是页面两侧却出现了大量空白区域,如果在4k
甚至更宽的屏幕下,空白区域大小会超过页面内容区域大小!
# 单列布局的实现
单列布局没有太多技术难点,通过将设置布局容器(最大)宽度以及**左右边距为auto
**即可实现
# 两列布局
两列布局使用频率也非常的高,实现效果就是将页面分割成左右宽度不等的两列,宽度较小的列设置为固定宽度,剩余宽度由另一列撑满。为了描述方便,我们暂且称宽度较小的列父元素为次要布局容器,宽度较大的列父元素为主要布局容器。
# 示例网站
Ant Design 文档,蓝色区域为主要内容布局容器,侧边栏为次要内容布局容器:
这种布局适用于内容上具有明显主次关系的网页,比如 API 文档页面中左侧显示内容导航,右侧显示文档描述;又比如后台管理系统中左侧显示菜单栏,右侧显示配置页面。相对于单列布局,在屏幕宽度适配方面处理得更好。当屏幕宽度不够时,主要内容布局容器优先显示,次要内容布局容器改为垂直方向显示或隐藏,但有时候也会和单列布局搭配使用,作为单列布局中的子布局使用。(响应式布局)
# 两列布局的实现
使用 flex 布局实现两列布局:
第 1 步,写好 HTML 结构。这里为了查看方便,我们为布局容器设置背景颜色和高度。
<style>
/* 为了方便查看,给布局容器设置高度和颜色 */
main,aside {
height: 100px;
}
main {
background-color: #f09e5a;
}
aside {
background-color: #c295cf;
}
</style>
<div>
<main>主要布局容器</main>
<aside>次要布局容器</aside>
</div>
第 2 步,将布局容器水平排列:
<style>
.wrap {
display: flex;
flex-direction: row-reverse;
}
.main {
flex: 1;
}
.aside {
flex: 1;
}
</style>
<div class="wrap">
<main class="main">主要布局容器</main>
<aside class="aside">次要布局容器</aside>
</div>
第 3 步,调整布局容器宽度:
<style>
.wrap {
display: flex;
flex-direction: row-reverse;
}
.main {
flex: 1;
}
.aside {
width: 200px;
}
</style>
<div class="wrap">
<main class="main">主要布局容器</main>
<aside class="aside">次要布局容器</aside>
</div>
第 4 步,消除副作用,比如浮动造成的高度塌陷。由于使用 flex 布局没有副作用,所以不需要修改,代码和效果图同第 3 步。
第 5 步,增加媒体查询。
<style>
.wrap {
display: flex;
flex-direction: row-reverse;
flex-wrap: wrap;
}
.main {
flex: 1;
}
.aside {
width: 200px;
}
@media only screen and (max-width: 1000px) {
.wrap {
flex-direction: row;
}
.main {
flex: 100%;
}
}
</style>
<div class="wrap">
<main class="main">主要布局容器</main>
<aside class="aside">次要布局容器</aside>
</div>
# 三列布局
三列布局按照左中右的顺序进行排列,通常中间列最宽,左右两列次之。
# 示例网站
登录 GitHub 后,蓝色区域为宽度最大的中间列:
CSDN 首页,这是 3 列布局的第二种实现方式,蓝色部分就是 2 列布局的主要布局容器,而它的子元素又使用了 2 列布局。
3 列布局和 2 列布局类似,也有明确的主次关系,只是关系层次增加了一层。下面我们来看看如何实现这些布局。
# 三列布局的实现
我们使用浮动float
实现三列布局:
第 1 步,写好 HTML 结构,为了辨认方便,我们给布局容器设置背景色和高度。
<style>
/* 为了方便查看,给布局容器设置高度和颜色 */
.main, .left, .right {
height: 100px;
}
.main {
background-color: red;
}
.left {
background-color: green;
}
.right {
background-color: blue;
}
</style>
<div class="wrap">
<main class="main">main</main>
<aside class="left">left</aside>
<aside class="right">right</aside>
</div>
第 2 步,让布局容器水平排列:
<style>
.main, .left, .right {
float: left;
}
</style>
<div class="wrap">
<main class="main">main</main>
<aside class="left">left</aside>
<aside class="right">right</aside>
</div>
第 3 步,调整宽度,将主要布局容器 main 撑满,次要布局容器 left 固定 300px,次要布局容器 right 固定 200px。
这里如果直接设置的话,布局容器 left 和 right 都会换行,所以我们需要通过设置父元素 wrap 内边距来压缩主要布局 main 给次要布局容器留出空间。同时通过设置次要布局容器边距以及采用相对定位调整次要布局容器至两侧。
<style>
.main, .left, .right {
float: left;
}
.wrap {
padding: 0 200px 0 300px;
}
.main {
width: 100%;
}
.left {
width: 300px;
position: relative;
left: -300px;
margin-left: -100%;
}
.right {
position: relative;
width: 200px;
margin-left: -200px;
right: -200px;
}
</style>
<div class="wrap">
<main class="main">main</main>
<aside class="left">left</aside>
<aside class="right">right</aside>
</div>
第 4 步,消除副作用。我们知道使用浮动会造成高度塌陷,如果在父元素后面添加新的元素就会产生这个问题。所以可以通过伪类来清除浮动,同时减小页面宽度,还会发现次要布局容器 left 和 right 都换行了,但这个副作用我们可以在第 5 步时进行消除。
<style>
.main, .left, .right {
float: left;
}
.wrap {
padding: 0 200px 0 300px;
}
.wrap::after {
content: '';
display: block;
clear: both;
}
.main {
width: 100%;
}
.left {
width: 300px;
position: relative;
left: -300px;
margin-left: -100%;
}
.right {
position: relative;
width: 200px;
margin-left: -200px;
right: -200px;
}
</style>
<div class="wrap">
<main class="main">main</main>
<aside class="left">left</aside>
<aside class="right">right</aside>
</div>
第 5 步,利用媒体查询调整页面宽度较小情况下的显示优先级。这里我们仍然希望优先显示主要布局容器 main,其次是次要布局容器 left,最后是布局容器 right。
<style>
.main, .left, .right {
float: left;
}
.wrap {
padding: 0 200px 0 300px;
}
.wrap::after {
content: '';
display: block;
clear: both;
}
.main {
width: 100%;
}
.left {
width: 300px;
position: relative;
left: -300px;
margin-left: -100%;
}
.right {
position: relative;
width: 200px;
margin-left: -200px;
right: -200px;
}
@media only screen and (max-width: 1000px) {
.wrap {
padding: 0;
}
.left {
left: 0;
margin-left: 0;
}
.right {
margin-left: 0;
right: 0;
}
}
</style>
<div class="wrap">
<main class="main">main</main>
<aside class="left">left</aside>
<aside class="right">right</aside>
</div>
这种 3 列布局的实现,就是流传已久的“圣杯布局”,但标准的圣杯布局没有添加媒体查询。