CSS布局 圣杯和双飞翼
圣杯布局和双飞翼布局
圣杯布局和双飞翼布局是前端工程师需要日常掌握的重要布局方式。两者的功能相同,都是为了实现一个两侧宽度固定,中间宽度自适应的三栏布局,都遵循了以下要点:
- 两侧宽度固定,中间宽度自适应
- 中间部分在DOM结构上优先,以便先行渲染
- 允许三列中的任意一列成为最高列
- 只需要使用一个额外的
<div>
标签
1. 圣杯布局
结构
<div class="container">
<div class="main">中间</div>
<div class="left">左边</div>
<div class="right">右边</div>
</div>
样式
.container {
/* 初始化 */
height: 100px;
background-color: wheat;
/* 防止left和right遮住main */
padding: 0 100px;
/* 防止转行 */
min-width: 100px;
}
.left,
.right {
/* 初始化 */
background-color: mediumslateblue;
width: 100px;
height: 100px;
float: left;
}
.main {
/* 初始化 */
width: 100%;
height: 100px;
background-color: mediumseagreen;
float: left;
}
.left {
/* 回到上一行开头 */
margin-left: -100%;
/* 移动到父元素padding区域 */
position: relative;
left: -100px;
}
.right {
/* 回到上一行结尾 */
margin-left: -100px;
/* 移动到父元素padding区域 */
position: relative;
right: -100px;
}
实现过程
- 给main,left,right加浮动,left,right宽100px,main宽度100%;
- 左右元素设置margin-left,到达上一行左右两端
- main部分区域被left,right遮掉了, 设置container左右padding为100px,然后相对定位移动left,right位置
- 设置container最小宽度100px防止窗口缩小转行
2. 双飞翼布局
结构
<div class="container">
<div class="main">中间</div>
</div>
<div class="right">右边</div>
<div class="left">左边</div>
样式
body {
min-width: 300px;/* 防止换行 */
}
.container {
/* 初始化 */
width: 100%;
height: 100px;
background-color: wheat;
}
.main {
height: 100px;
margin: 0 100px;
background-color: mediumseagreen;
}
.left {
/* 初始化 */
width: 100px;
height: 100px;
background-color: mediumslateblue;
/* 转到上一行 */
margin-left: -100%;
}
.right {
/* 初始化 */
width: 100px;
height: 100px;
background-color: mediumturquoise;
/* 转到上一行 */
margin-left: -100px;
}
.left,
.right,
.container {
/* 给三个盒子加浮动从而可以通过margin换行 */
float: left;
}
实现过程
- 设置main的左右margin(或者padding)使其内容在container中间,流出两边位置给left,right
- 设置container,left,right的浮动
- 设值left和right的margin使其回到上一行
- 防止换行,设置三者的父元素min-width=left的宽度+right的宽度+container的最小宽度(假设100)=300px
通过对圣杯布局和双飞翼布局的介绍可以看出,圣杯布局在DOM结构上显得更加直观和自然,且在日常开发过程中,更容易形成这样的DOM结构(通常<aside>
和<article>
/<section>
一起被嵌套在<main>
中);而双飞翼布局在实现上由于不需要使用定位,所以更加简洁,且允许的页面最小宽度通常比圣杯布局更小。
其实通过思考不难发现,两者在代码实现上都额外引入了一个<div>
标签,其目的都是为了既能保证中间栏产生浮动(浮动后还必须显式设置宽度),又能限制自身宽度为两侧栏留出空间。
3. 其他实现方式
若不考虑兼容性,可以使用更简单的实现方式:
flex布局
<div class="container">
<div class="main"> 中间 </div>
<div class="left">左边</div>
<div class="right">右边</div>
</div>
.container {
display: flex;
background-color: mediumslateblue;
}
.main {
flex: 1;
background-color: mediumseagreen;
}
.left {
order: -1;/* 排列顺序 */
flex: 0 0 100px;
background-color: mediumslateblue;
}
.right {
flex: 0 0 100px;
background-color: mediumslateblue;
}
calc计算
/* 省略... */
.main, .left, .right {
float: left;
}
.main {
margin: 0 100px;/* 左右边距 */
width: calc(100% - 200px);/* 计算宽度 */
}
border-box
.main,
.left,
.right {
float: left;
}
.main {
width: 100%;
box-sizing: border-box;
padding: 0 100px;/* padding值从width里减 */
}