IFC(Inline Formatting Context)内联格式化上下文
与IFC之对应的是BFC : block formating context(块级格式化上下文),BFC在网页布局中的应用场景更是极其丰富,了解它会了解很多bug出现的原因,以及自行找到解决办法。为了更好地理解IFC,建议首先了解下列三个知识点
IFC跟BFC一样,它不是一个元素,不是一种属性,而是一种环境,一种上下文,一种布局特性。
符合以下条件即会生成一个IFC
块级元素中仅包含内联级别元素
形成条件非常简单,需要注意的是当IFC中有块级元素插入时,会产生两个匿名块将父元素分割开来,产生两个IFC,这里不做过多介绍。
IFC布局规则
引用w3c的IFC布局规则如下:
高度抽象版(不易读懂)
- 子元素水平方向横向排列,并且垂直方向起点为元素顶部。
- 子元素只会计算横向样式空间,【padding、border、margin】,垂直方向样式空间不会被计算,【padding、border、margin】。
- 在垂直方向上,子元素会以不同形式来对齐(vertical-align)
- 能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框(line box)。行框的宽度是由包含块(containing box)和与其中的浮动来决定。
- IFC中的"line box"一般左右边贴紧其包含块,但float元素会优先排列。
- IFC中的"line box"高度由 CSS 行高计算规则来确定,同个IFC下的多个line box高度可能会不同。
- 当 inline-level boxes的总宽度少于包含它们的line box时,其水平渲染规则由 text-align 属性值来决定。
- 当一个"inline box"超过父元素的宽度时,它会被分割成多个boxes,这些 boxes 分布在多个"line box"中(一部分留在原来的"line box",一部分换行排列在下一个"line box"里)。如果子元素未设置强制换行的情况下,"inline box"将不可被分割,将会溢出父元素。
白话版(易读懂)
在IFC中,内联元素在水平方向上一个接一个的排布,其中,容器之间水平方向上的margin,padding,border方向上是有效的。他们垂直方向上的对齐由vertical-align来决定,比如底部(bottom)或顶端(top)对齐,或者基线(baseline)对齐。他们对齐完了之后形成的这个四方块儿区域,叫做一个line box(行框)。
一个line box的宽度由包含它的元素的宽度和包含它的元素里面有没有float元素来决定,而高度由内部元素中实际高度最高的元素而计算出来。
//其实这句话解释了为什么内联元素是不能设置垂直方向的padding,margin等,因为即使设置了,也不会影响line box的高度,可能会在每个浏览器的表现各异,但大多数不会达到预期的效果。
line box的高度是足够高来包含他内部的容器们的,也可能比它包含的容器们都高(比如在基线对齐的时候),如图:
当他包含的内部容器的高度小于line box的高度的时候,内部容器的垂直位置由自己的vertical这个属性来确定。当内部的容器盒子太多了一个line box装不下来,他们折行之后会变成两个或者多个line box, line box们相互之间垂直方向不能分离,不能重叠。
一般来说,line box的左边缘挨着包含它的元素的左边缘,并且右边缘挨着包含它的元素的右边缘,浮动元素会在包含他们的元素的 边缘和line box的边缘之间,所以,虽然在同一个IFC下的line box们通常拥有相同的宽度(就是包含他们的容器的宽度),但是也会因为浮动元素的捣乱,导致line box们的可用宽度产生了变化不一样了。在同一个Ifc下的line box们的高度也会不一样(比如说,一个line box里有个比较大的image,他就高了)。
补充图方便理解:
如果一个line box 里的内联元素们的宽度总和小于这个line box的宽度,那么他们在这个line box里的水平方向的排布方式由 text-align这个属性来决定,如果这个属性被设置成了“justify”,可以使这些盒子在剩余空间内拉伸(除了inline-table 和 inline-block的元素)。//实现类似两端对齐的效果,但不是所有浏览器都支持。
当内联元素的宽度超过了line box的宽度,那么它会折行分裂成了几个line box,如果这个元素里面的内容不可以折行,例如只有一个字,或者white-space设置了nowrap/pre。那么内联元素会溢出line box。
当一个内联元素分裂时,分裂处的 margins, borders 和 padding不会有任何视觉效果(或者其他任何分裂,只要是有多个line box)。
line box 的生存条件是在IFC中并且包含inline-level元素,如果line box里没有文本,空白,换行符,内联元素,也没有其他的存在IFC环境中的元素,(如inline-block,inline- table,images等),将会被视为零高度,也将会被视为没有意义。
补充:在IFC的环境中,是不能存在block-level元素的,如果将block-level元素插入到IFC中,那么此IFC将会被破坏掉, 而block-level元素前的元素和block-level元素后的元素将会各自自动产生一个匿名容器其包围,这个匿名的容器内部环境将是一个新的 IFC。
例1:
P是一个块元素,它包含了5个内联元素,其中,有三个是匿名的。
- 匿名: “Several”
- EM: “emphasized words”
- 匿名: “appear”
- STRONG: “in this”
- 匿名: “sentence, dear.”
这段代码里,在line box里,有5个inline的元素,P建立了包含line box的容器箱。
如果这个P的宽度足够,将会产生唯一的一个line box。如下图:
如果P的宽度不够,将会被分割成多个line box。如下图:
例2:
- margin,在emphasized前和word之后水平方向上起了作用。分割处无作用,垂直方向无作用。
- padding,在emphasized前和word之后水平方向上起了作用。分割处无作用,垂直方向无作用。
- border,看那个虚线的表现形式。
经过了上面的阐述,我们回到博客开使的问题上。实现未知尺寸的文本/元素/图片 在某个元素内垂直居中。
上面曾经说过:
在一个line box中,当他包含的内部容器的高度小于line box的高度的时候,内部容器的垂直位置由自己的vertical这个属性来确定。
那么,我们设想一下,如果手动创建一个IFC的环境,让line box的高度是包含块的高度的100%,让line box内部的元素使用vertical-align:middle,就可以实现垂直居中。
一个line box的高度由内部元素中实际高度最高的元素而计算出来。
所以,我们在line box中插入一个高度100%的inline-block元素。则会把整个line box撑高直到包含块的100%。
概念图:
其中,高级浏览器可以直接在外面的包含层使用:after来在内部追加创建一个伪元素,而低级浏览器不支持:after的写法,则在html模板中 创建一个空的元素, 设置其高度为100%则与包含层相同,宽度为零,内容为空,则可以实现将自己内部撑大为一个line box,但不占据任何空间。那么自己内部的其他元素可以通过转化为inline 或者 inline-block 来实现在line box中的垂直居中。表现形式就是在外面的包含层中垂直居中。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>IFC应用实例</title>
<meta name="copyright" content="www.ohweb.cn" />
<meta name="author" content="weinan" />
</head>
<body>
<style>
/* comm 核心部分 */
.g-ifc-wrap:after,
.g-ifc-wrap-after{content:'';height:100%;width:0;display:inline-block;*display:inline;*zoom:1;margin-left:-5px;font-size:0;vertical-align:middle;}
.g-ifc-item{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;}
/* test */
#test{height:300px;width:500px;background-color:#878787;border:3px solid #526f39;}
#test p{background-color:#7ff30a;color:#000;font-weight:bold;}
</style>
<div id="test" class="g-ifc-wrap">
<p class="g-ifc-item">我想要基于外面的容器居中</p>
<img class="g-ifc-item" alt="我也是" src="http://dh2.kimg.cn/v/upload/20140325/9aa6e7f4e477d9af9c463c5604070ed4.jpg?v=1395739057" />
<!--[if lte IE 7]><span class="g-ifc-wrap-after"></span>< ![endif]-->
</div>
</body>
</html>
表现形式如下:
chrome等高级浏览器:
小结 :
当我们详细的了解IFC的原理之后,可以更有自信的应用它来做很多事情。
例如有些网站会摒弃float这种bug多多的布局方式,而全部使用IFC的环境来进行布局(当然了,很精确的时候也需要解决inline-level元素之间的间隙)。
或者实现一些如图片文字的居中对齐,自适应高度等很多灵活的效果。
同时,当我们的网页产生一些bug的时候,我们也可以明白为何如此并且思考好的解决方法而不是去网上找“万金油”。这将使我们对自己的网页有了更深的掌控性。
本文转载自 https://www.cnblogs.com/weinan/p/3665766.html
作者:荒漠千蝶