一、三栏布局
问题:假设高度默认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;
}
                    
