CSS包含块Containing Block

包含块在《CSS权威指南》里就几句话介绍,W3C 里也说的很简单。但它是个很重要的基础知识

为什么理解包含块很重要!

使用 CSS 的 position布局,涉及到 top,right,bottom,left 这些定位属性时,你能十分自信的确定他们相对什么位置偏移吗。在未学习前我一直粗暴的认为包含块就是父元素,它们应该相对父元素偏移。

但是一个元素实际产生的范围框可以有四个。 元素框

  1. content edge内容区域产生的内容框。
  2. padding edge内边距边界产生的内边距框。padding为0时和内容框重合
  3. border edge 边框产生的范围框。border-width为0时和内边距框重合
  4. margin edge 外边距边界产生的外边巨框。margin为0时和边框重合

假设图中的元素 position 属性为 relative 。现在它有个尺寸 30px*30px 的子元素 position 为absolute,然后top:10px;left:10px. 这个子元素该相对上面四个框的哪一个定位呢(它的包含块是谁)? 如果这个子元素 position 也为 relative,那它的包含块会变吗?

包含块

浏览器在显示页面时,元素框的定位和尺寸的计算,都取决于一个矩形的边界,这个矩形,被称作包含块( containing block )。一般来说,元素生成的框会扮演它后代元素包含块的角色。我们称之为:一个(元素的)框为它的后代节点建造了包含块。包含块是一个相对的概念。“一个框的包含块”,指的是“该框所存在的那个包含块”,并不是它建造的包含块。每个元素都有属于它的包含块。

各种情况下元素框的包含块定义:

根元素的包含块称为初始包含块

  • 在 HTML 中,根元素是 html元素(尽管有的浏览器会不正确地使用 body元素)。
  • 初始包含块的 direction 属性与根元素相同。(direction 属性指定了块的基本书写方向,它还规定了表格列布局的方向、水平溢出的方向等。)
  • 初始包含块的宽度可以由根元素的 width 属性指定。如果该属性取值为“auto”,用户端提供初始宽度(如浏览器窗口宽度)。
  • 初始包含块的高度可以由根元素的 height 属性指定。如果该属性取值为“auto”,包含块的高度将调整以适应文档内容(即由其内容决定其高度)。
  • 初始包含块不可以被定位或浮动,用户端忽略根元素的 position 和 float 属性。

其它元素:

如果该元素的 position 为 relative 或 static,它的包含块由它最近的块级、单元格(table cell)或者行内块(inline-block)祖先元素的内容框创建。(大多数情况是父元素内容框)

  • 如果元素的position为fixed,包含块由浏览器窗口创建,就是浏览器窗口。

  • 如果元素position为absolute,包含块由最近的position属性为非static的祖先元素创建。

  • 如果该祖先元素是块元素,那么包含块的区域应该是该祖先元素的内边距边界【可写代码验证】

  • 如果该祖先元素是行内元素,包含块取决于祖先元素的direction属性:

  • 如果 'direction' 是 'ltr',包含块的顶、左边是祖先元素生成的第一个框的顶、左内边距边界(padding edges) ,右、下边是祖先元素生成的最后一个框的右、下内边距边界(padding edges)

  • 如果 'direction' 是 'rtl',包含块的顶、右边是祖先元素生成的第一个框的顶、右内边距边界 (padding edges) ,左、下边是祖先元素生成的最后一个框的左、下内边距边界 (padding edges)

  • 如果不存在这样的祖先元素,则元素的包含块为初始包含块。

包含块示例

<body id="body">  
<div id="div1">  
<p id="p1">这是第一个段落文本</p>  
<p id="p2">这是<em id="em1">第二段落<strong id="strong1">文本</strong></em></p>  
</div>  
</body>  

元素包含块关系表如下

创建框的元素 创建包含块的元素
htmlinitial C.B. (UA-dependent)
bodyhtml
div1body
p1div1
p2div1
em1p2
strong1p2

如果对 div1 设置绝对定位 #div1 { position: absolute; left: 50px; top: 50px }

则“div1”层的包含块不再是“body”,而是初始包含块(因为没有其它定位祖先框)。 如果再增加对“em1”的定位:

  #div1 { position: absolute; left: 50px; top: 50px }
  #em1  { position: absolute; left: 100px; top: 100px }

变动后的包含块关系表

创建框的元素 创建包含块的元素
htmlinitial C.B. (UA-dependent)
bodyhtml
div1initial C.B.
p1div1
p2div1
em1div1
strong1em1