上网游荡,意外间发现寒冬大神的关于CSS布局博客http://www.cnblogs.com/winter-cn/archive/2013/05/11/3072929.html和面试博客感觉有点意思,所以花点时间来梳理梳理。
大牛的问题是——position的哪些取值和行为
答案:normal flow、containing block、bfc、margin collapse,base line,writing mode,bidi。。。
了解基本概念:
- viewport:
展现网页的媒体,比如窗口或者某个区域,它的大小是有限制的,为了不被平台术语所束缚,我们给他起名viewport,中文意思就是视口。 - canvas:
而我们在渲染网页的时候通常并不知道我们需要多大的空间,而且这些空间通常尺寸会超过viewport的大小,于是实际上我们需要设想一个无限大的画布来绘制我们的元素,我们把它称为canvas。 - box:
element(元素)和node(节点)是大家很熟悉的概念,当我们做布局计算的时候,通常会把节点变成box,一个节点可能产生多个box,伪元素也会产生box。 - render tree: 对应于dom树,我们把box的包含关系构成的属性结构成为渲染树render tree
首先来看BFC,BFC(Block Formatting Context)块级格式化上下文
Formatting Context:指页面中的一个渲染区域,并且拥有一套渲染规则,他决定了其子元素如何定位,以及与其他元素的相互关系和作用。
BFC:块级格式化上下文,它是指一个独立的块级渲染区域,只有Block-level BOX参与,该区域拥有一套渲染规则来约束块级盒子的布局,且与区域外部无关。
简单示例:
<html>
<head><title>囧</title></head>
<body>
<div style="width:300px;height:50px;"></div>
<div style="width:300px;height:20px;"></div>
<div style="height:50px;"></div>
<div style="width:300px;height:50px;"></div>
</body>
</html>
简单地说,BFC就是像例子里面一样顺次竖着排块级盒的一种上下文。
BFC的产生
既然上文提到BFC是一块渲染区域,那这块渲染区域到底在哪,它又是有多大,这些由生成BFC的元素决定,CSS2.1中规定满足下列CSS声明之一的元素便会生成BFC。
- 根元素
- float的值不为none
- overflow的值不为visible
- display的值为inline-block、table-cell、table-caption
position的值为absolute或fixed
看到有道友文章中把display:table也认为可以生成BFC,其实这里的主要原因在于Table会默认生成一个匿名的table-cell,正是这个匿名的table-ccell生成了BFC。
canvas会设立一个BFC,这也是最外层的formatting context了,问题的复杂性在于有些块级盒内部也可以产生BFC(至少它必须也能包含块级盒),于是说BFC是可以嵌套滴
<html>
<head><title>囧</title></head>
<body>
<div style="width:300px;height:100px;">
<div style="width:300px;height:20px;"></div>
<div style="height:50px;"></div>
</div>
<div style="height:50px;"></div>
</body>
</html>
不是所有块级盒内部都可以产生BFC,比如说要是这盒里面连块级盒都没有,都是行内盒那就产生IFC。
<html>
<head><title>囧</title></head>
<body>
<div style="width:300px;height:100px;overflow:visible;">
<span>囧</span><span>囧囧</span>
</div>
<div style="height:50px;"></div>
</body>
</html>
上例中,第一个div中overflow:visible不产生BFC,它的子元素直接搞进自己外层的BFC;但是第二个div产生的是BFC,所以只要它的子节点里面有一个块级盒,它就产生BFC,那些行内元素,会自动套一个匿名的块级行盒。
overflow:visible这个限制只对所谓的块盒(既包含块级盒、自己又是块级盒)存在,有些盒内部也能包含块级元素,但是它本身又不是块级元素(比如display为table-cell、inline-block、或者盒本身是flex item等),因为外面不是BFC,所以它们不论如何一定会给包含的块级盒创建一个新的BFC出来。
总结:
BFC的约束规则
浏览器对于BFC这块区域的约束规则如下:
- 生成BFC元素的子元素会一个接一个的放置。垂直方向上他们的起点是一个包含块的顶部,两个相邻子元素之间的垂直距离取决于元素的margin特性。在BFC中相邻的块级元素外边距会折叠。
生成BFC元素的子元素中,每一个子元素做外边距与包含块的左边界相接触,(对于从右到左的格式化,右外边距接触右边界),即使浮动元素也是如此(尽管子元素的内容区域会由于浮动而压缩),除非这个子元素也创建了一个新的BFC(如它自身也是一个浮动元素)。
有道友对它做了分解,我们直接拿来:
- 内部的Box会在垂直方向上一个接一个的放置
垂直方向上的距离由margin决定。(属于同一个BFC的两个相邻Box在流方向上margin会发生重叠) - 每个元素的左外边距与包含块的左边界相接触(从左向右),即使浮动元素也是如此。(这说明BFC中子元素不会超出他的包含块,而position为absolute的元素可以超出他的包含块边界)
- BFC的区域不会与float的元素区域重叠 计算BFC的高度时,浮动子元素也参与计算
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然
看到以上的几条约束,让我想起学习css时的几条规则
IFC
IFC里面可能有文字、行内元素混合排布:
- 内部的Box会在垂直方向上一个接一个的放置
<html>
<head><title>囧</title></head>
<body>
<div style="">
<span>囧</span>囧囧囧<span>囧囧</span>
</div>
</body>
</html>
对于一个正常的”行盒”来说,文字总是垂直居中排布的。
在纵向,文本排布主要受line-height属性影响,在有行内盒参与的情况下就复杂了,
一个行内盒的vertical-align可以有这样几种取值:
baseline
sub
super
top
text-top
middle
bottom
text-bottom
它也可以是某一指定高度。根据行内盒的对齐方式,它有可能把这行盒向上或者向下”撑大”,造成超过行高的情况。
所以行盒在BFC中占据的实际高度,很可能大于line-height。
文字的baseline很好理解,而行内元素则比较复杂,特别是当行内元素自身又是容器的时候: