包含块(containing block)是可视化格式模型中得一个重要概念。CSS2中,很多框的位置和尺寸的计算都基于一个被称为包含块的长方形盒子的四边。通常地,生成的框表现为其派生框的包含块;我们说一个框“建立”了它的派生框的包含块。短语“一个框的包含块”意味着“该框所存在的那个包含块”,而不是它所生成的块。
一、包含块的判定与范围
包含块判定的总流程,一行图就可以说明,这里注明下这张图的来源地址http://w3help.org/zh-cn/kb/008/。
然后根据这张图,我们来一个个的分析。
根元素
根元素,就是处于文档树最顶端的元素,它没有父节点。
用户代理(比如浏览器)选择根元素作为包含块(称之为初始包含块)。在(X)HTML中,根元素是html元素(尽管有的浏览器会不正确地使用body元 素)。而初始包含块的direction属性与根元素相同。
static与relative定位元素
如果该元素的定位为 "relative" 或者 "static",它的包含块由它最近的块级、单元格(table cell)或者行内块(inline-block)祖先元素的内容框创建。元素如果未声明 ‘position‘ 特性,那么就会采用 ‘position‘ 的默认值 "static"。还是结合一个例子来说明下:
<table> <tr> <td> <div> <span> <em>txt</em> other txt </span> </div> </td> </tr> </table>
元素 | 包含块 |
html | 初始包含块 |
body | html |
table | body |
td | table |
div | td |
txt | div |
块级、单元格(td,th)、行内块,牢牢抓住这几点,上面的表格就不难理解了。td的包含块不是tr,因为tr不属于这三种;txt的包含块是div,因为em也不属于这三种。
fixed定位元素
如果元素是fixed定位元素,那么它的包含块是当前可视窗口(viewport)。
absolute定位元素
absolute这个元素相信大家用得比较多也比较熟悉了,我们在这里不会细致去谈它的表现和用处,这些东西会在这个系列文章的绝对定位这一节中具体去分析。我们在这里只讨论绝对定位元素的包含块。
总得来说,绝对定位元素的包含块由离它最近的 ‘position‘ 属性为 ‘absolute‘、‘relative‘ 或者 ‘fixed‘ 的祖先元素创建,也就是非static祖先元素。但是如果当这个祖先元素为行内元素的时候,包含块就要取决于祖先元素的direction元素了。下面我们结合例子具体说明。
1.非static祖先元素不为行内元素时,absolute元素的包含块由这个非static祖先元素的padding edge来生成。(什么是padding edge可以看下面一张图)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>absolute定位</title> <style> div{position:absolute; left: 50px; top:50px;} </style> </head> <body> <table> <tr> <td> <div> <span> <em>txt</em> other txt </span> </div> </td> </tr> </table> </body> </html>
如上,就是前面一个例子,不过我们对div设置了position:absolute,这样,div的包含块不再是body,而变成了初始包含块,这里也就是html,因为div没有其他非static的定位祖先元素了。
如果我们给上面的例子加上下面的style:
div{position:absolute; left:50px; top:50px;}
em{position:absolute; left:100px; top:100px;}
那么包含块的关系就变成下面这样了:
元素 | 包含块 |
html | 初始包含块 |
body | html |
table | body |
td | table |
div | 初始包含块 |
em | div |
txt | em |
注意几个变化,em与txt,em是因为它的祖先元素中有div这个非static定位元素,txt是因为现在em是块级元素了。
2.下面,我们来结合例子谈谈非static祖先元素为行内元素时,absolute元素的包含块是怎么一个表现。
1).direction为ltr时,包含块的顶、左边是祖先元素生成的第一个框的顶、左内边距边界(padding edges) ,右、下边是祖先元素生成的最后一个框的右、下内边距边界(padding edges)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>direction:ltr</title> </head> <body> <p style="border:1px solid red; width:200px; padding:20px;"> T <span style="background-color:#C0C0C0; position:relative; border:1px red solid;"> 这段文字从左向右排列,红 XX 和 蓝 XX 和黄 XX 都是绝对定位元素,它的包含块是相对定位的SPAN。 可以通过它们绝对定位的位置来判断它们包含块的边缘。 <em style="position:absolute; color:red; top:0; left:0;">XX</em> <em style="position:absolute; color:yellow; top:20px; left:0;">XX</em> <em style="position:absolute; color:blue; bottom:0; right:0;">XX</em> </span> </p> <p style="border:1px solid red; width:200px; padding:20px;"> TEXT TEXT TEXT <span style="background-color:#C0C0C0; position:relative;"> 这段文字从左向右排列,红 XX 和 蓝 XX 和黄 XX 都是绝对定位元素,它的包含块是相对定位的SPAN。 可以通过它们绝对定位的位置来判断它们包含块的边缘。 <em style="position:absolute; color:red; top:0; left:0;">XX</em> <em style="position:absolute; color:yellow; top:20px; left:0;">XX</em> <em style="position:absolute; color:blue; bottom:0; right:0;">XX</em> </span> </p> </body> </html>
看了这张图应该一目了然了。以上代码中,文字采取默认从左到右的方式排列。红 XX 和 蓝 XX 和黄 XX 都是绝对定位元素,它的包含块是相对定位的 SPAN。 它们定位需要参照包含块,按照标准来说,它们包含块的左顶边是 SPAN 形成的第一个框的顶、左内边距边,包含块的右、下边是 SPAN 生成的最后一个框的右、下内边距边界。
包含块的宽度可能是负的。如上面例子里的第二个p,包含块的边界无法围成一个区域,在这种情况下,包含块的宽度是负的。
2).如果 ‘direction‘ 是 ‘rtl‘,包含块的顶、右边是祖先元素生成的第一个框的顶、右内边距边界(padding edges) ,左、下边是祖先元素生成的最后一个框左、下内边距边界(padding edges) 。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>direction:rtr</title> </head> <body> <p style="border:1px solid red; width:200px; padding:20px; direction:rtl;"> T <span style="background-color:#C0C0C0; position:relative; border:1px red solid;"> 这段文字从左向右排列,红 XX 和 蓝 XX 和黄 XX 都是绝对定位元素,它的包含块是相对定位的SPAN。 可以通过它们绝对定位的位置来判断它们包含块的边缘。 <em style="position:absolute; color:red; top:0; left:0;">XX</em> <em style="position:absolute; color:yellow; top:20px; left:0;">XX</em> <em style="position:absolute; color:blue; bottom:0; right:0;">XX</em> </span> </p> </body> </html>
同样很清晰了。
不过有一点要注意,行内元素内形成的包含块,在各浏览器中各不相同,存在兼容性问题。这个大家可以具体去测试一下。
二、总结
其实包含块这个在标准中是放在可视化格式模型细节这一章来讲的,但是考虑到这个系列很多地方用到了这个概念,还是在这里先提一下。然后包含块这个概念涉及到宽高度的自动、absolute元素定位和float定位的很多问题,是很重要也是值得去了解的。这篇文章成文比较仓促,很多细节还没完善,后续会继续完善,也不排除有遗漏盒错误,如有发现还请指正。
参考资料:
1.http://w3help.org/zh-cn/kb/008/
2.http://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#containing-block-details