一、三栏布局
问题:假设高度默认100px
,请写出三栏布局,其中左栏、右栏各为300px
,中间自适应。
初学者想到的答案有两种:
- 方法1:浮动
方法2:绝对定位
但要求你能至少写出三四种方法,才算及格。剩下的方法如下:
方法3:
flexbox
。移动开发里经常用到。- 方法4:表格布局
table
。虽然已经淘汰了,但也应该了解。 - 方法5:网格布局
grid
浮动
使用 calc
左侧设置左浮动,右侧设置右浮动,中间宽度设置为用 100% 减 左右栏的宽度
<head>
<style>
div {
height: 100px;
background-color: red;
}
.mid {
float: left;
width: calc(100% - 600px);
background-color: aqua;
}
.left {
float: left;
width: 300px;
}
.right {
float: right;
width: 300px;
}
</style>
</head>
<body>
<div class="left"></div>
<div class="mid"></div>
<div class="right"></div>
</body>
使用 margin —— 双飞翼布局
利用浮动以及外边距负值。 一个 container 包裹 middle、left、right。 middle 放在第一个,然后 left、right 通过 margin 将自身偏移到对应左右位置。 这样做 middle 会占整一行,需要在 middle 中添加一个 content,设置 content 的 margin。
也就是实际上,middle 的内容都应该放在 content 中。
<head>
<style>
body {
margin: 0;
}
.container {
height: 100px;
}
.container>div {
float: left;
height: 100px;
}
.left,
.right {
background-color: red;
width: 200px;
}
.left {
margin-left: -100%;
}
.right {
margin-left: -200px;
}
.middle {
width: 100%;
background-color: aqua;
}
.content {
margin-left: 200px;
margin-right: 200px;
}
</style>
</head>
<body>
<div class="container">
<div class="middle">
<div class="content">456</div>
</div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
使用 padding —— 圣杯布局
利用浮动以及内边距。 一个 container 包裹 middle、left、right。给 container 设置左右 padding。 middle 放在第一个,然后 left、right 通过
left/right
属性将自身偏移到对应左右位置。为什么 left、right 需要偏移呢? 因为 container 设置 padding 后,缩小了 width,不是占一整行。 left 通过
margin-left: 100%
偏移值是 container 的 width,不占一整行。
<head>
<style>
body {
margin: 0;
}
.container {
height: 100px;
padding-right: 200px;
padding-left: 200px;
}
.container>div {
float: left;
height: 100px;
}
.left,
.right {
background-color: red;
width: 200px;
}
.left {
margin-left: -100%;
position: relative;
left: -200px;
}
.right {
margin-left: -200px;
position: relative;
right: -200px;
}
.middle {
width: 100%;
background-color: aqua;
}
</style>
</head>
<body>
<div class="container">
<div class="middle"></div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
绝对定位
使用 div 标签作为容器,包裹左、中、右三个部分。
左侧设置为绝对定位,
left:0px
。 右侧设置为绝对定位,right:0px
。 中间设置为绝对定位,left
和right
都为300px
,即可。中间的宽度会自适应。
<head>
<style>
div {
height: 100px;
}
.container {
position: relative;
}
.left {
position: absolute;
width: 300px;
left: 0;
background: red;
}
.right {
position: absolute;
width: 300px;
right: 0;
background: red;
}
.mid {
position: absolute;
left: 300px;
right: 300px;
background: aqua;
}
</style>
</head>
<body>
<div class="container">
<div class="left"></div>
<div class="mid"></div>
<div class="right"></div>
</div>
</body>
flex 布局
将左中右所在的容器设置为
display:flex
,设置两侧的宽度后,然后让中间的flex: 1 0 auto
,即可。
<head>
<style>
div {
height: 100px;
}
.container {
display: flex;
}
.left,
.right {
flex: 0 0 300px;
background-color: red;
}
.mid {
flex: 1 0 auto;
background-color: aqua;
}
</style>
</head>
<body>
<div class="container">
<div class="left"></div>
<div class="mid"></div>
<div class="right"></div>
</div>
</body>
table 布局
设置整个容器的宽度为
100%
,设置三个部分均为表格,然后左边的单元格为300px
,右边的单元格为300px
,即可。中间的单元格会自适应。
<head>
<style>
div {
height: 100px;
}
.container {
display: table;
width: 100%; /* 设置这个,mid 才能自适应宽度 */
}
.left,
.right {
display: table-cell;
width: 300px;
background-color: red;
}
.mid {
display: table-cell;
background-color: aqua;
}
</style>
</head>
<body>
<div class="container">
<div class="left"></div>
<div class="mid"></div>
<div class="right"></div>
</div>
</body>
grid 布局
使用 div 标签作为容器,包裹左、中、右三个部分。 设置 contianer 为 grid 布局,设置 grid-template-rows 和 grid-template-columns
<head>
<style>
.container {
display: grid;
width: 100%;
grid-template-rows: 100px;
grid-template-columns: 300px auto 300px;
}
.left,
.right {
background-color: red;
}
.mid {
background-color: aqua;
}
</style>
</head>
<body>
<div class="container">
<div class="left"></div>
<div class="mid"></div>
<div class="right"></div>
</div>
</body>
扩展
五种方法的优缺点
- 考虑中间模块的高度问题
- 兼容性问题:实际开发中,哪个最实用?
方法1:浮动:
- 优点:兼容性好。
- 缺点:浮动会脱离标准文档流,因此要清除浮动。我们解决好这个问题即可。
方法:2:绝对定位
- 优点:快捷。
- 缺点:导致子元素也脱离了标准文档流,可实用性差。
方法3:flex 布局(CSS3 中出现的)
- 优点:解决上面两个方法的不足,flex布局比较完美。移动端基本用 flex布局。
方法4:table 布局
- 优点:表格布局在很多场景中很实用,兼容性非常好。因为IE8不支持 flex,此时可以尝试表格布局
- 缺点:因为三个部分都当成了单元格来对待,此时,如果中间的部分变高了,其会部分也会被迫调整高度。但是,在很多场景下,我们并不需要两侧的高度增高。
什么时候用
flex
布局 or table 布局,看具体的场景。二者没有绝对的优势,也没有绝对的不足。
方法5:网格布局
- CSS3中引入的布局,很好用。代码量简化了很多。
PS:面试提到网格布局,说明我们对新技术是有追求的。
延伸:如果题目中去掉高度已知
问题:题目中,如果去掉高度已知,我们往中间的模块里塞很多内容,让中间的模块撑开。会发生什么变化?哪个布局就不能用了?
答案是:flex 布局、table 布局、grid 布局可以通用,其他三个布局都不能用了。
二、居中布局
水平居中
1. 行内元素
实现在块级元素内部的 行内元素水平居中,对
inline
、inline-table
、inline-block
、inline-flex
元素都有效。
.inline-center-parent {
text-align: center;
}
2. 块级元素
2.1 使用 margin
.block-center {
margin: 0 auto;
}
2.2 设置为 inline-block
,并在父元素添加 text-align:center
.parent {
text-align: center;
}
.son {
display: inline-block;
}
2.3 使用 flex 布局
.parent {
display: flex;
justify-content: center;
}
2.4 使用绝对定位
- left + transform
.parent { position: relative; } .son { position: absolute; left: 50%; transform: translateX(-50%) }
垂直居中
1. 单行的行内元素(
将行内元素的inline-
)元素垂直居中line-height
和height
高度设置一致.vertical-middle { display: inline | inline-table | inline-block | inline-flex; height: 高度; line-height: 高度; }
2. 多行元素垂直居中
2.1 table 布局 + vertical-align
```css .parent { display: table; height: 500px; }
.son { display: table-cell; vertical-align: middle; }
<a name="z6i94"></a>
#### 2.2 flex 布局
1. 主轴为水平方向时,使用 `align-items: center`
```css
.parent {
display: flex;
align-items: center;
}
- 主轴为垂直方向是,使用
justify-content: center
当然,这只是符合垂直居中的概念,但第二种的效果 和 第一种的效果是不一样的。
.parent {
display: flex;
flex-direction: column;
justify-content: center;
}
3. 块级元素居中(利用定位)
3.1 居中元素高度已知(top + margin-top)
由于元素的 margin 如果设置百分比,是相对于元素的包含块的宽高的。
所以需要元素的高度已知,设置为准确值。
.parent {
position: relative;
height: 100vh;
}
.son {
position: absolute;
height: 100px;
top: 50%;
margin: -50px;
}
缺点:父元素空间不够时, 子元素可能不可见(当浏览器窗口缩小时,滚动条不出现时)
3.2 居中元素高度未知(top + transform)
.parent {
position: relative;
height: 100vh;
}
.son {
position: absolute;
height: 100px;
top: 50%;
transform: translateY(-50%);
}
3.3 居中元素高度未知(top & bottom: 0)
.parent {
position: relative;
height: 100vh;
}
.son {
position: absolute;
height: 100px;
top: 0;
bottom: 0;
margin: auto 0; /* 这个起关键作用 */
}
水平垂直居中
1. 已知宽高的元素(绝对定位 + margin)
.parent {
position: relative;
height: 100vh;
}
.son {
position: absolute;
width: 200px;
height: 200px;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -100px;
}
2. 未知宽高的元素(绝对定位 + transform)
.parent {
position: relative;
height: 100vh;
}
.son {
position: absolute;
width: 200px;
height: 200px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%)
}
3. 未知宽高的元素(flex 布局)
.parent {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
4. 未知宽高的元素(grid 布局)
.parent {
display: grid;
height: 100vh;
}
.son {
margin: auto;
}