CSS的两种格式化上下文:BFC和IFC
CSS的两种格式化上下文
文章包含很多个人理解,如果错误,欢迎指出~
在看本文之前,你要对CSS的盒子模型,Block-Level元素,Inline-Level元素有所了解,具体可参考CSS的盒子模型、三种元素类型。
本文具体解读了CSS针对block-level元素和inline-level元素设计的两种格式化上下文:BFC(Block Formatting Context)和IFC(Inline Formatting Context),它们规定了block-level元素和inline-level元素在对应格式化上下文中的渲染规则。了解上述内容是清楚理解网页排版的基础,当然在此基础上,还要进一步掌握CSS的几种定位方法,浮动等内容,才能理解和设计更加复杂的网页布局。
格式化上下文
格式化上下文即Formatting context,它是指页面上的一个局部独立渲染区域,根据Formatting context中包含的是元素类型的不同,分为块级格式上下文BFC和行内格式化上下文IFC,不同的格式化上下文对应着不同的渲染规则,来告诉页面多个Block-Level元素或是多个Inline-Level元素在页面中该如何布局。需要注意,在BFC中只会包含Block-Level元素,同样的,在IFC中只会包含Inline-Level元素。
块级格式化上下文BFC(Block Formatting context)
触发BCF的方法,下面这些元素都会产生一个新的BFC
- 根元素;
float属性不为none;position为absolute或fixed;display为inline-block, table-cell, table-caption, flex, inline-flex;overflow不为visible;
BFC包括如下特性
BFC内部的Block-Level元素会在垂直方向,一个接一个地放置;
两个相邻的处于同个BFC的Block-Level元素的margin会发生重叠;这里包括相邻的兄弟元素和嵌套元素;发生重叠的具体条件,和重叠的方式,请看http://www.cnblogs.com/ningyn0712/p/5369024.html
BFC内部的Block-Level元素的left outer edge与它的container Box的left inner edge重合;
BFC不会与它同级的float元素发生重叠;
利用这个特性可以很方便的实现动态两栏的结构。对于处于同一个BFC中Block-Level元素和一个float元素,它们是会发生重叠的,如Example2所示;但如果我们将Block-Level元素触发成一个新的BFC,这个Block-Level元素就会自动通过缩小box宽度避免float元素重叠,如Example 3所示;但是实验发现,通过设置overflow实现的BCF不能完全避免重叠,这个Block-Level元素的margin区域还是会与float元素发生重叠,如Example 4所示;希望有人可以帮忙解释原因;
Example 2: 在id为container-div的div标签中放置一个id为th1-div的浮动div标签和一个id为th2-div的普通标签;
<style type="text/css">
#container-div
{
background: cornflowerblue;
height: 200px;
}
#th1-div
{
float: left;
height: 100px;
width: 100px;
background: red;
}
#th2-div
{
height: 100px;
background: orange;
}
</style> <div id="container-div">
<div id="th1-div">
</div>
<div id="th2-div">
</div>
</div>

**Example 3** :在id为container-div的div标签中放置一个id为th1-div的浮动div标签和一个id为th2-div的普通标签;通过设置#th2-div的overflow: hidden;来触发#th2-div的BFC,以达到#th1-div与#th2-div不重叠的目的;
<style type="text/css">
#container-div
{
background: cornflowerblue;
height: 200px;
}
#th1-div
{
float: left;
height: 100px;
width: 100px;
background: red;
margin-right: 10px;/*为了清楚看出两个div是分离的*/
}
#th2-div
{
height: 100px;
background: orange;
overflow: hidden;/*触发BFC*/
}
</style>
<div id="container-div">
<div id="th1-div">
</div>
<div id="th2-div">
</div>
</div>

**Example 4**: 根据Example 3的方法触发#th2-div的BFC,同时设置#th2-div的margin-left: 10px;按理说,因为BFC特性,#th1-div与#th2-div应该不会发生重叠,结果应该与Example 3的图一样,但是实验发现,#th2-div的margin区域和#th1-div是重叠的,如下图所示;
<style type="text/css">
#container-div
{
background: cornflowerblue;
height: 200px;
}
#th1-div
{
float: left;
height: 100px;
width: 100px;
background: red;
/*margin-right: 10px;*/
}
#th2-div
{
height: 100px;
background: orange;
margin-left: 10px;
overflow: hidden;/*触发BFC*/
}
</style>
<div id="container-div">
<div id="th1-div">
</div>
<div id="th2-div">
</div>
</div>

BFC就是一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
利用这个特性,我们可以解决父子元素margin重叠的问题。根据BFC特性2我们知道,在同一个BFC里面嵌套的父子Block-Level元素的margin区域是会发生重叠的,如Example 5所示;但如果我们触发父元素生成一个新的BFC,那么它的子元素就不再和父元素处于同一个BFC,从而解决父子元素margin重叠的问题,如Example 6所示。
Example 5: 在Example 5中,#container-div创建了一个新的BFC,#container-div嵌套着#th1-div,#th1-div嵌套着#th2-div,同时#th1-div设置了margin-top: 10px,#th2-div设置了margin-top: 20px;我们可以看到最终#th1-div和#th2-div基于border-top对齐,两者margin-top重叠;
<style type="text/css">
#container-div
{
background: cornflowerblue;
height: 300px;
overflow: hidden;/*触发BFC*/
}
#th1-div
{
height: 200px;
width: 200px;
background: green;
margin-top: 10px;
}
#th2-div
{
height: 100px;
width: 100px;
background: orange;
margin-top: 20px;
}
</style>
<div id="container-div">
<div id="th1-div">
<div id="th2-div">
</div>
</div>
</div>

Example 6: 在Example 5的基础上,我们通过设置overflow: hidden;让#th1-div创建了属于一个BFC,从而让#th1-div和#th2-div不再属于同一个BFC,结果显示#th1-div和#th2-div的margin区域不再重叠,它们成功以我们希望的看到的布局展示。
<style type="text/css">
#container-div
{
background: cornflowerblue;
height: 300px;
overflow: hidden;/*触发BFC*/
}
#th1-div
{
height: 200px;
width: 200px;
background: green;
margin-top: 10px;
overflow: hidden;/*触发BFC*/
}
#th2-div
{
height: 100px;
width: 100px;
background: orange;
margin-top: 20px;
}
</style>
<div id="container-div">
<div id="th1-div">
<div id="th2-div">
</div>
</div>
</div>

计算BFC的高度时,浮动元素也参与计算;
利用这个特性,我们可以解决浮动元素造成的父元素塌陷问题。 如Example 7所示,默认情况下,浮动元素不会撑开父元素的高度;但是当我们触发了父元素的BFC,如EXample 8所示,这时父元素在计算高度时,会把浮动元素也计算在内,也就解决了父元素塌陷的问题。
Example 7: 在#th1-div里面放入一个左浮动的#th2-div元素,因为浮动元素脱离了文档流,所以#th2-div元素无法撑开#th1-div的高度,如图所示;
<style type="text/css">
#container-div
{
background: cornflowerblue;
height: 300px;
overflow: hidden;/*触发BFC*/
}
#th1-div
{
width: 200px;
background: green;
}
#th2-div
{
height: 100px;
width: 100px;
background: orange;
float: left;
}
</style>
<div id="container-div">
<div id="th1-div">
<div id="th2-div">
</div>
</div>
</div>

Example 8: 在Example 8的基础上,通过设置overflow: hidden;触发#th1-div的BCF,使得#th1-div在计算高度的时候会把浮动元素也计算进去,因此#th1-div的高度就变大了。
<style type="text/css">
#container-div
{
background: cornflowerblue;
height: 300px;
overflow: hidden;/*触发BFC*/
}
#th1-div
{
width: 200px;
background: green;
}
#th2-div
{
height: 100px;
width: 100px;
background: orange;
float: left;
}
</style>
<div id="container-div">
<div id="th1-div">
<div id="th2-div">
</div>
</div>
</div>

行内格式化上下文IFC(Inlinel Formatting context)
在了解IFC之前,必须对Inline-Level元素的Inline-box概念有所了解,需要知道Inline-Level元素在行中的占位是由Inline-box确定的,而非Inline-Level元素的盒子模型确定。同时你需要知道line box的概念,它其实就是包含多个处于一行的Inline-Level元素的行框,多个连续的Inline-Level元素按照从左到右,从上大小的顺序被放置在多个line boxs中。
IFC所规定的渲染规则其实就是对Inline-Level元素在line box中布局的几个关键问题进行了解答,具体如下:
多个连续的Inline-Level元素是怎样被拆分到多个line boxs中的?
我的理解是:IFC会先将所有的元素一个个依次首尾相接排列到一起,合并成一个完整的流,然后再确定流中不可拆分的部分,最后将这个流拆分布局到多个不定宽度的line boxs。在上述这个由多个元素组成的流中,不可拆分的部分包括没有空格的连续字符串、单个英文或其他字符、可替换的Inline-Level元素。
为什么要强调先要合并成完整的流这一过程,主要是想说明在IFC中不是以元素作为最小不可拆分单元的,元素里面的内容可能也可以拆分成多个部分布局到多个line boxs中,比如Example 9,元素之间也可能不可拆分,比如Example 10。
Example 9:当一个span里面的内容大于line box的宽度,它的内容自动拆分成两个部分,分布在两行(两个line box)中;
<style type="text/css">
#container-div
{
width: 100px;
height: 200px;
background: cornflowerblue;
}
span:nth-child(1)/*伪类选择器,选择span标签,同时它要是其父元素的第一个子元素*/
{
color: orange;
background:rebeccapurple;
}
span:nth-child(2)
{
color: green;
background: goldenrod;
}
</style> <div id="container-div">
<span >This is a span</span>
</div>

Example 10:两个span元素的宽度总和已经大于line box的宽度了,但是第二个元素没有进行换行布局。这是为什么,把它们想成一个整体就好理解了,因为第一个span里面的字符串和第二个span里面的字符串之间不存在空格,因此IFC把他们的内容理解成一个连续的字符串,他们也就成了不可拆分的整体,第二个span也就没有办法进行换行了。
<style type="text/css">
#container-div
{
width: 100px;
height: 200px;
background: cornflowerblue;
}
span:nth-child(1)/*伪类选择器,选择span标签,同时它要是其父元素的第一个子元素*/
{
color: orange;
background:rebeccapurple;
}
span:nth-child(2)
{
color: green;
background: goldenrod;
}
</style> <div id="container-div">
<span >ItIsSpan1</span><span>ItIsSpan2</span>
</div>

line box的宽度和高度由什么决定的?
line box的宽度由包含块和浮动元素决定:当不存在浮动元素时,line box的宽度等于包含块的内容区域的宽度;否则,因为Inline-Level元素会环绕浮动元素布局的特性,line box的宽度会比包含块的内容区域的宽度小。
line box的高度是由它包含的所有元素的Inline-box决定的,line box的上边界由行中最高的Inline-box上边界确定,line box的下边界由行中最低的Inline-box下边界确定;需要注意不要误以为line box的高度是由行内最高的元素决定;
Inline-Level元素在line boxs中的水平布局由什么决定的?
如果line box内部内所有Inline-box的总宽度小于line box的宽度,它们在line box中的布局由父元素的
text-align属性决定;所以通过设置text-align属性可以实现在父元素中居中的效果,如Example 11所示;Example 11:通过设置父元素的
text-align:center就能实现行内元素居中效果。<style type="text/css">
#container-div
{
width: 100px;
height: 200px;
background: cornflowerblue;
text-align: center;/*设置内容水平居中*/
}
span:nth-child(1)/*伪类选择器,选择span标签,同时它要是其父元素的第一个子元素*/
{
color: orange;
background:rebeccapurple;
}
span:nth-child(2)
{
color: green;
background: goldenrod;
}
</style> <div id="container-div">
<span >A span</span>
</div>

Inline-Level元素在line boxs中的垂直布局由什么决定的?
Inline-Level元素在line box中的垂直位置由元素的
vertical-align属性决定;最后一点,line box之间不会存在空隙,也不会发生重叠;
参考资料:
[2] 深入理解BFC
[3] 在网页布局中合理使用inline formating context(IFC)
CSS的两种格式化上下文:BFC和IFC的更多相关文章
- css的两种盒子模型
css的两种盒子模型:W3C标准盒子模型.IE盒子模型 两者的相同之处:都包含margin.border.padding.content 两者的不同之处:W3C标准盒子模型的content部分不包含其 ...
- 引入外部CSS的两种方式及区别
1.CSS的两种引入方式 通过@import指令引入 @import指令是CSS语言的一部分,使用时把这个指令添加到HTML的一个<style>标签中: 要与外部的CSS文件关联起来,得使 ...
- css中margin重叠和一些相关概念(包含块containing block、块级格式化上下文BFC、不可替换元素 non-replaced element、匿名盒Anonymous boxes )
平时在工作中,总是有一些元素之间的边距与设定的边距好像不一致的情况,一直没明白为什么,最近仔细研究了一下,发现里面有学问:垂直元素之间的margin有有互相重叠的情况:新建一个BFC后,会阻止元素与外 ...
- WordPress引入css/js两种方法
WordPress引入css/js 是我们制作主题时首先面对的一个难点,任何一款主题都要加载自己的css,js,甚至很有可能还需要加载Jquery文件,网上方法特多,说法不一,我们今天借鉴wordpr ...
- CSS的两种盒模型
盒模型一共有两种模式,一种是标准模式,另一种就是怪异模式. 当你用编辑器新建一个html页面的时候你一定会发现最顶上都会有一个DOCTYPE标签,例如: <!DOCTYPE HTML PUBLI ...
- css中两种居中方式text-align:center和margin:0 auto 的使用场景
关于使用text-align:center和margin:0 auto 两种居中方式的比较 前言:最近由于要学习后端,需要提前学习一部分前端知识,补了补css知识,发现狂神在讲这一部分讲的不是特别清楚 ...
- 块级格式化上下文(BFC)
一.什么是BFC 具有BFC属性的元素也属于普通流定位方式,与普通容器没有什么区别,但是在功能上,具有BFC的元素可以看做是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且具有普通容 ...
- css垂直居中 两种方法
在前端面试的时候我们经常会被问道怎样使一个元素在页面垂直居中呢,这也是一个老生常谈的问题了. 解决的方法基本都是使用定位来实现 div{display: fixed;left: 50%;top: 50 ...
- 引入css的两种方式
摘自:https://www.cnblogs.com/gyjWEB/p/4831646.html 在HTML中引入css的其中的两个方法: 1.如果使用链接式,需要使用如下的语句引入外部css文件: ...
随机推荐
- SpringBoot 入门 Demo
SpringBoot 入门 Demo Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从 ...
- Python + gevent模块对单个接口进行并发测试 1
本文知识点 利用gevent模块进行并发测试 代码如下 from gevent import monkey monkey.patch_all() import requests import geve ...
- scrapy 请求和响应
scrapy Request类的一些参数意义 url: 就是需要请求,并进行下一步处理的url callback: 指定该请求返回的Response,由那个函数来处理. method: 一般不需要指定 ...
- Docker镜像的导出和载入
https://www.cnblogs.com/lishidefengchen/p/10564765.html
- ASP.NET中MD5的加密方式很简单
在ASP.NET中MD5的加密方式很简单,代码如下: FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5&quo ...
- Qt随笔 - QSettings
QSettings类提供了持久的跨平台应用程序设置. 嗯,一句话概括QSettings-- 创建 来看一下原型: QSettings::QSettings(const QString &org ...
- BZOJ 3224 Treap
部分还没调到满意的程度,效率比splay略好 #include<bits/stdc++.h> using namespace std; const int maxn = 1e6+11; u ...
- SQL批量提交修改业务
把你需要批量提交修改的东西在内存中修改完毕 然后执行以下代码 SqlConnection conn = new SqlConnection(ConnectionString);SqlDataAdapt ...
- 基于PHPExcel的常用方法总结
// 通常PHPExcel对象有两种实例化的方式// 1. 通过new关键字创建空白文档$phpexcel = newPHPExcel();// 2. 通过读取已有的模板创建$phpexcel =PH ...
- 第十六章:自定义push notification sound
前面一节已经讲过如何在ionic中集成jpush,这样我们的hybrid app在部署到ios或者android上面的时候,就可以接收通知了.如果不满足系统自带的声音,可以通过一些方式来播放自定义的通 ...