概念
布局流方案
1.普通流 (normal flow)
元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行,块级元素则会被渲染为完整的一个新行,除非另外指定,否则所有元素默认都是普通流定位。
可能存在:
- 相邻元素margin重叠
- 子元素margin 影响到父元素
2.浮动流 (float)
在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。会占据空间,脱离的文档流,导致父级无法计算他的子元素高度。
可能存在:
- 浮动后的子元素脱离了文档流,父容器无法计算子元素高度。
- 浮动元素覆盖了相邻的元素
3.定位流(position)
在定位流中,绝对定位元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响,而元素具体的位置由绝对定位的坐标决定。
盒子概念
1.块级元素
display:block;
h1,p,ul,ol div, table,form,footer
排版方式:从上到下,每一个都独占一行,垂直排版。
2.行内元素
display:inline; display:inline-block;
a,i (倾斜),b(加粗),em(倾斜,强调语义),span(定义文档中的节),mark(标记加背景色)code,
排版方式:从左到右,依次紧挨,放不下换行,水平排版。
Formatting Context 格式化上下文
它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。 包含4种
- BFC : 块级
Block-格式化上下文, CSS2.1 标准 - IFC : 行内级
Inline-格式化上下文, CSS2.1 标准 - TFC : 网格级
Table-格式化上下文, CSS2.1 标准 - FFC : 弹性级
Flex-格式化上下文, CSS3 标准 - GFC : 网格级
Grid-格式化上下文, CSS3 标准
1.BFC 块级
1.定义
Block Formatting Context
具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,外部也不会影响内部,并且 BFC 具有普通容器所没有的一些特性。 BFC 理解为一个封闭的大箱子。
注意: 块级有两种情况
- 做父容器的场景
- 自己是子元素的场景
2.特征:
父容器:
- 容器能够包含浮动元素,即浮动元素变回普通流,占用普通流空间。
- 和其他浮动的子元素产生边界
- 清除的样式规则只适用与同一个上下文。 子元素:
- 清除浮动只清除在他前面的元素浮动。
3.布局规则
- 每个子元素都是垂直布局,独占一行
- 垂直的高度= 子元素的边框内高度 + 子元素的margin-top + margin-bottom
- 水平的宽度= 子元素的边框内宽度 + 子元素的margin-left + margin-right
- 上下的子元素margin-top和bottom会重叠,左右left,right不会重叠。
3.触发条件:
- body 根元素
- 浮动元素:float 除 none 以外的值
- 绝对定位元素:position 除了默认值static和relative 以外的值 absolute、fixed
- display 为 inline-block、flex、inline-flex、table、table-cell、table-caption
- overflow 除了 默认值visible 以外的值 (hidden、auto、scroll)
- display:flow-root 最新的css语法兼容差
4.解决场景
1. 解决父容器高度坍塌, BFC可以包含计算浮动的元素的高度,
<html>
<head>
<style>
* { margin: 0; padding: *;}
.outer {
border: 2px solid red;
}
.box {
width: 100px;
height: 100px;
background-color: gray;
float: left;
}
</style>
</head>
<body>
<div class="outer">
<div class="box"></div>
</div>
</body>
</html>
由于容器内元素浮动,脱离了文档流,所以容器只剩下 2px 的边距高度。
如果使触发容器的 BFC,那么容器将会包裹着浮动元素。
.outer {
border: 2px solid red;
overflow: hidden;/*打开BFC*/
}
最优办法
不使用bfc,clear:botn清除浮动 + 添加伪类实现。
.outer:after {
display: table;
height:0; /*部分浏览器需要指定table高度*/
content: "";
clear: both;
}
2. 两个相邻的元素margin外边距垂直方向-会发生重叠
<html>
<head>
<style>
.outer {
border: 1px solid green;
}
.box {
width: 100px;
height: 100px;
margin: 50px;
}
.box1 {
background-color: black;
}
.box2 {
background-color: red;
}
</style>
</head>
<body>
<div class="outer">
<div class="box box1"></div>
<div class="box box2"></div>
</div>
</body>
</html>
解决办法,在其中一个box外部包裹一个bfc,
<html>
<head>
<style>
.outer {
border: 1px solid green;
}
.box {
width: 100px;
height: 100px;
margin: 50px;
}
.box1 {
background-color: black;
}
.box2 {
background-color: red;
}
.outbox {
overflow: hidden;/*打开bfc模式 ,两个div都开启bfc模式*/
}
</style>
</head>
<body>
<div class="outer">
<div class="box box1"></div>
<div class="outbox">
<div class="box box2"></div>
</div>
</div>
</body>
</html>
最优办法
使用伪类,在父容器outbox通过伪类,在box2前面多添加一个子元素并且设置为bfc。
.outbox {
}
.outbox::before {
display:table;
content:""; /*伪类必须设置内容 不然无效*/
}
3. 父子关系,子元素margin影响父元素的margin
<html>
<head>
<style>
* { margin: 0; padding: *;}
.outer {
width: 300px;
height: 300px;
background-color: red;
}
.box {
width: 100px;
height: 100px;
background-color: black;
margin-top: 50px;
}
</style>
</head>
<body>
<div class="outer">
<div class="box"></div>
</div>
</body>
</html>
这时候父容器包裹成bfc,这样bfc的变化都不影响外部。
.outer {
width: 300px;
height: 300px;
background-color: red;
overflow: hidden;
}
缺点:如果父容器有其他定位内容需要显示,会被切割。
其他办法
- 父容器设置padding-top 代替子元素的margin-top
缺点: 改变了父元素的大小,需要改变IE盒子模型。
.outer {
width: 300px;
height: 300px;
background-color: red;
padding-top : 50px;
box-sizing: border-box; /*改变为IE盒子 content = content + padding +border*/
}
- 父容器添加border 添加额外的边框,可以使父容器不被元素影响。
但是而且改变了父元素的大小,而且元素位置也变化了。
.outer {
width: 300px;
height: 300px;
background-color: red;
border: 1px solid transparent; /*设置一个透明的边框*/
box-sizing: border-box; /*改变为IE盒子 content = content + padding +border*/
}
.box {
width: 100px;
height: 100px;
background-color: black;
margin-top: 50px;
margin-left: -1px;/*修复父容器border的1px*/
}
- 父容器多添加一个排第一的子元素
table 不占用空间,缺点 :多了一个元素
<html>
<head>
</head>
<body>
<div class="outer">
<table></table> <!-- 新增一个标签 -->
<div class="box"></div>
</div>
</body>
</html>
- 父容器多添加一个排第一的子元素
最优方法
使用伪类,在父容器outer通过伪类,在box前面多添加一个子元素并且设置为bfc。
outer::before {
display:table;
content:"";
}
4. 实现两列布局,左边固定,右边自适应,BFC可以阻止元素被浮动元素覆盖,
<html>
<head>
<style>
* { margin: 0; padding: *;}
.box1 {
width: 100px;
height: 100px;
background: lightblue;
float : left;
}
.box2 {
width: 200px;
height: 200px;
background: red;
overflow: hidden;
}
</style>
</head>
<body>
<div class="box1">我是一个左浮动的元素</div>
<div class="box2">我是一个没有设置浮动XXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
</body>
</html>
在box2 添加overflow:hidden 打开bfc模式,
.box2 {
width: 200px;
height: 200px;
background: red;
overflow: hidden;/*打开BFC*/
}
2.IFC 行内
定义
行内格式化上下文 Inline Formatting Contexts
在同一个父容器下,多个行内子元素会形成 IFC
line-box
Line box是由一行同级或多级inline或inline-box元素组成的区域
行内框一个接一个地排列,排列顺序和书写方向一致。
- 能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框(
line box)。
触发条件:
- 块级元素中仅包含内联级别元素 display为 inline,inline-block
特点:
- 内部的盒子会在水平方向,一个个地放置,水平的外边距,内边距,边框是可以有的;
- 是当
IFC中有块级元素插入时,会产生两个匿名块将父元素分割开来,产生两个IFC;
横向相关
IFC中的行框一般左右边贴紧其包含块,但float元素会优先排列;- 当
IFC中盒子的总宽度少于包含它们的行框时,其水平渲染规则由text-align属性值来决定; - 当一个行内元素超过父元素的宽度时,它会被分割成多个盒子,这些盒子分布在多个行框中。如果子元素未设置强制换行的情况下,行框将不可被分割,将会溢出父元素。
- float元素会位于IFC与line box之间,使得line box宽度缩短。
IFC的行框的宽度:由包含块和与其中的浮动来决定;
纵向相关
IFC的高度:由最高盒子的高度决定;(不受到竖直方向的padding/margin影响)- 当一行不够放置的时候会自动切换到下一行;
- 根据
vertical-align属性垂直对齐,middle实现垂直居中。 - 同个ifc下的多个line box高度会不同。
3.TFC-表格
定义
表格格式化上下文,Flex Formatting Context
触发条件
使用表格嵌套内容+定义表格宽度。
<style>
table{
width: 100%;
}
</style>
<table>
<thead>
<th>标题1</th>
<th>标题2</th>
</thead>
<tbody>
<td>aa</td>
<td>bb</td>
</tbody>
</table>
特点
上下对齐,左右对齐,文字默认居中
4.FFC-弹性
定义
弹性格式化上下文 Flex Formatting Context
触发条件
display:flex; /*块级元素*/
/*或者*/
display:inline-flex; /*行内元素*/
特点
容器内容自适应伸缩,可以根据设置的flex值 来控制占用空间比重。
5.GFC-网格
定义
网格格式化上下文 GridLayout Formatting Context
触发条件
display:grid;
特点
能有一个独立的渲染区域,可以在网格容器上定义网格行和列,为每一个网格定义位置和空间。