常见定位方案
- 普通流(normal flow)
在普通流中, 元素按照其HTML中的先后位置自上而下布局, 在这个过程中, 行内元素水平排列, 直到行内被占满后换行; 块级元素则会渲染为完整的新行。除非另外指定,否则所有元素默认都是普通流定位, 也可以说, 普通流中元素的位置由该元素在HTML文档中的位置决定。
- 浮动(float)
在浮动布局中,元素首先按照普通流的位置出现, 然后根据浮动的方向尽可能的向左边或者向右边偏移, 其效果与印刷版中的文本环绕相似。
- 绝对定位(absolute positioning)
在绝对定位布局中, 元素会整体脱离文档流, 因此绝对定位元素不会对其兄弟元素造成影响, 而元素具体的位置由绝对定位的坐标决定。
BFC
BFC即Block Formatting Contexts(块级格式化上下文), 它属于上述定位方案的普通流。
具有BFC特性的元素可以看作是隔离了的独立容器, 容器里面的元素不会在布局上影响到外面的元素, 并且BFC具有普通容器所没有的一些特性。
通俗的说, 可以把BFC理解为一个封闭的大箱子, 箱子内的元素无论怎么折腾, 都不会影响到外部元素。
1.触发BFC
只要元素满足下面任意一条件即可触发BFC特性:
- body 根元素
- 浮动元素: float 除 none以外的值
- 绝对定位: position(absolute/fixed)
- display除了visible以外的值(hidden、auto、scroll)
2. BFC特性及应用
- 同一个BFC下,外边距会发生折叠
<section>
<style>
div {
width: 100px;
height: 100px;
background: #f00;
margin: 100px;
}
</style>
<body>
<div></div>
<div></div>
</body>
</section>
从效果上看, 因为两个div元素都处于同一个BFC容器下(这里指的是body元素)所以第一个div的下边距和第二个div的上边距发生了重叠, 因此两个盒子之间距离只有100px,而不是200px。
这不是css的bug,我们可以理解为是一种规范, 如果想要避免外边距重叠, 可以将其放在不同的BFC容器中。 如下:
<section>
<style>
.container{
overflow: hidden;
}
p {
width: 100px;
height: 100px;
background: #f00;
margin: 100px;
}
</style>
<div class="container">
<p></p>
</div>
<div class="container">
<p></p>
</div>
</section>
这个时候, 两个盒子边距就变成了200px
-
BFC可以包含浮动的元素(清除浮动)
浮动的元素都会脱离普通文档流:
<section>
<style>
.first {
width: 100px;
background: #f00;
float: left;
}
.second {
width: 200px;
height: 200px;
border: 1px #00f solid;
}
</style>
<div class="first">
我是第一个元素我是第一个元素我是第一个元素
</div>
<div class="second">
我是第二个元素我是第二个元素我是第二个元素我是第二个元素我是第二个元素我是第二个元素
</div>
</section>
这个时候第二个元素被第一个浮动元素所部分覆盖,(文本信息不会被浮动元素覆盖)如果想避免元素被覆盖, 可触发第一个元素的BFC特性, 在第二个元素中加入overflow: hidden; 就会变成如下效果:
这个方法可以用来实现两列自适应布局
IFC
IFC, inline Formatting Contexts, 也就是 ”内联格式化上下文“。
符合以下任何一条件即会生成一个IFC
- 块级元素中仅包含内联级别元素
形成条件非常简单, 需要注意的是当IFC中有块级元素插入时, 会产生两个匿名块将父元素分割开来,产生两个IFC。
IFC布局规则:
- 子元素水平方向横向排列,并且垂直方向起点为元素顶部。
- 子元素只会计算横向样式空间,(padding, border, margin), 垂直方向样式空间不会被计算(padding, border, margin )。
- 在垂直方向上, 子元素会以不同形式来对齐(vertical-align)。
- 能把在一行上的框都完全包含进去的一个矩形区域, 被称为该行的行框(line box)。行框的宽度是由包含块(containing box)和与其中的浮动来决定的。
- IFC中的”line box“一般左右边贴紧其包含块, 但float元素会优先排列。
- IFC中的”line box“高度由css行高计算规则来确定, 同个IFC的多个line box高度可能会不同。
- 当line-level boxes 的总宽度少于包含它们的line box时, 其水平渲染规则由 text-align属性值来决定。
- 当一个”inline box“超过父元素的宽度时, 它会被分割成多个boxes, 这些boxes分布在多个”line box“中。 如果子元素未设置强制换行的情况下, ”inline box“将不可被分割, 将会溢出父元素。
相对于BFC, IFC的规则一大推, 很少会有人耐心看下去, 举个例子大概明白其特性。
很多时候,上下间距不生效可以使用IFC来解释
<section>
<style>
.wrap {
display: inline-block;
border: 1px #f00 solid;
}
span {
margin: 20px;
background: #00f;
}
</style>
<div class="wrap">
<span>文本一</span>
<span>文本二</span>
</div>
</section>
上里可以看出, span左右margin撑开, 上下margin未撑开, 符合IFC规范:只计算横向样式空间, 不计算纵向样式空间。
多个元素水平居中
<section>
<style>
.wrap{
border: 1px #f00 solid;
width: 200px;
text-align: center;
}
span{
background: #00f;
}
</style>
<div class="wrap">
<span>文本一</span>
<span>文本二</span>
</div>
</section>
水平排列规则根据IFC容器的text-align值来排列,可以用来实现多个子元素的水平居中。
float元素优先排列
<section>
<style>
.wrap{
border: 1px #f00 solid;
width: 200px;
}
span{
background: #00f;
}
.fl{
float: left;
}
</style>
<div class="wrap">
<span>文本一</span>
<span>文本二</span>
<span class="fl">文本三</span>
</div>
</section>
IFC中具备float属性值的元素优先排列, 在很多场景中用来在文章段落开头添加”tag“可以用到。
利用IFC还可以做很多其他的事情,例如:解决元素垂直居中、多个文本元素行高不一致排列的混乱。