视觉格式化模型细节
包含块的定义
元素(生成的)盒的位置有时候是根据一个特定的矩形计算的,叫做元素的包含块(containing block)。元素包含块的定义如下:
元素 |
包含块 |
其为根元素。 |
其包含块是一个被称为初始包含块的矩形。对连续媒体,尺寸取自视口的尺寸,并且被固定在画布开始的位置;对于分页媒体就是页区。初始包含块的direction属性与根元素相同。 |
其position为static或relative。 |
其包含块由最近的块容器祖先盒的内容边界形成。 |
其position为fixed。 |
其包含块由连续媒体的视口或分页媒体的页区建立。 |
其position为absolute。 |
包含块由最近的position为absolute、relative或fixed的祖先建立。 如果该祖先是一个行内元素,包含块就是围绕着该元素生成的第一个和最后一个行内盒的内边距框的边界框(bounding box)。在CSS2.1中如果该行内元素被跨行分割了,那么包含块是未定义的。 否则,包含块由该祖先的内边距边界形成。 |
如果没有这样的祖先,包含块就是初始包含块。 |
分页媒体中,一个绝对定位的元素是相对于其包含块定位的,忽略所有的页结束符(就像文档是连续的意义),该元素可能被拆分到多页。对于绝对定位的内容,如果被解析到一个除元素所在的页面之外的其他页面上的位置,或者是当前页上已经为打印渲染好了的位置,打印机可能把该内容让在:
- 当前页上的另一个位置
- 后续页
- 直接忽略它
内容宽度:width属性
该属性指定了盒的内容宽度,不适用于非替换的行内元素。非替换的行内元素盒的内容宽度是它里面渲染的内容(的内容宽度)。在“控制盒”一节讲到过,行内盒都被排列在行框里,行框的宽度由他们的包含块决定(也就是行框宽度是自适应包含块宽度的),但可能因为浮动的出现而被缩短。
属性值的含义如下:
- <length>:一个固定值。
- <percentage>:一个百分比值,根据生成的盒的包含块的宽度来计算。如果包含块的宽度取决于该元素的宽度,那么产生的布局在CSS2.1中是未定义的。注意:对于那些包含块是基于一个块容器元素的绝对定位元素,百分比是根据这个元素的内边距框的宽度计算的。这与CSS1不同,(CSS1中)百分比宽度总是根据父级元素的内容框计算的。
- auto:取决于其他属性的值,见下面章节。
计算width、margin-left、margin-right、left和right
元素的width、margin-left、margin-right、left和right属性用于布局的值,取决于生成盒的类型以及相互影响(用于布局的值有时被称为应用值)。原则上,应用值与计算值一样,都是把auto替换成一些合适的值,百分比相对其包含块来计算,但也存在例外。以下情况需要加以注意:
行内非替换元素
width不适用:
- margin-left和margin-right计算值为auto时,应用值为0。
- left和right的值由相对定位中的规则确定。
行内替换元素
width计算值 |
height计算值 |
是否有固有宽度 |
是否有固有高度 |
是否有固有比例 |
width应用值 |
auto |
|
是 |
|
|
固有宽度 |
auto |
无 |
有 |
有 |
高度的应用值*固有比例 |
|
有计算值 |
|||||
auto |
无 |
无 |
有 |
未定义,但规范建议如果包含块的宽度不依赖替换元素的宽度,那么width的应用值根据用于常规流中块级非替换元素的约束方程来计算。 |
|
以上条件全部不满足。 |
width应用值为300px。如果300px对适应设备来说太宽了,UA应该根据设备的最大的比例为2:1的矩形来代替。 |
margin-left和margin-right为auto时的计算值为0。
left和right的值由相对定位中的规则确定。
常规流中的非替换inline-block元素
如果width是auto,应用值就与浮动元素一样是自适应宽度。
计算值为auto的margin-left或者margin-right的应用值变为0。
常规流中的替换inline-block元素
与行内替换元素完全一致。
常规流中的块级非替换元素
其他属性的应用值,必须保证如下约束:
margin-left + border-left + padding-left + width +
margin-right + border-right + padding-right = 包含块的宽度
- width不为auto
- 如果margin-left和margin-right都是auto,那么它们的应用值相等。这回让该元素相对于其包含块居中。
- 如果border-left + padding-left + width + border-right + padding-right再加上所有不为auto的margin-left或margin-right的结果大于包含块的宽度,那么所有margin-left或margin-right的auto值会被当做0。
- 如果以上的属性计算值都不是auto,就说该值被过渡限制了,其中一个应用值将与其计算值不同。如果包含块的direction属性为ltr,margin-right的指定值会被忽略,并且重新计算该值,以便让等式成立。如果direction的值为rtl,就换成margin-left。
- width为auto,则所有其他的auto值都变为0,并且width由产生的等式得出。
- 如果有且仅有一个值被指定为auto,则其应用值由等式得出。
left和right的值由相对定位中的规则确定。
常规流中的块级替换元素
width的应用值由行内元素决定。然后,用非替换的块级元素的规则来确定外边距。
(注意,这里的替换元素要求是“块级”的,即如果要让input等替换元素居中显示,必须加上display:block。)
浮动的非替换元素
如果margin-left或者margin-right的计算值为auto,其应用值为0。
如果width的计算值为auto,应用值就是自适应(shrink-to-fit)宽度。
自适应宽度的计算与自动表格布局算法去算一个表格单元的宽度类似。粗略地讲:通过格式化不含除显式换行外的换行来计算首选宽度(perferred width),然后计算首选最小宽度(perferred minimum width),例如,通过尝试所有可能的换行。CSS2.1没有定义准确的算法。第三步,算出可用宽度(available width):这种情况下,就是包含块的宽度减去margin-left、border-left、padding-left、margin-right、border-right、padding-right以及所有相关滚动条的宽度的应用值。
那么自适应宽度就是:min(max(首选最小宽度,可用宽度),首选宽度)
left和right的值由相对定位中的规则确定。
浮动的替换元素
如果margin-left或者margin-right的计算值为auto,其应用值为0。
width的应用值见行内替换元素宽度的计算。
left和right的值由相对定位中的规则确定。
绝对定位的非替换元素
就本节和下节而言,术语(元素的)“静态位置”,大致指的是元素在常规流中的位置。更精确地:
- 静态位置包含块(static-position containing block)是一个假想盒的包含块,(假想盒)将是该元素的第一个盒,它指定了position的值为static并且float为none。
- left的静态位置是从包含块的左边界到作为该元素的第一个盒的假象盒的左外边距边界的距离。如果假想盒在包含块的左边,那么值为负。
- right的静态位置是从包含块的右边界到与上面相同的假想盒的右外边距边界的距离。如果假想盒在包含块边的左边,那么值为正。
但不用实际计算假想盒的尺寸,UA可以随意猜测它可能的位置。出于计算静态位置的目的,fixed定位元素的包含块为初始包含块,而不是视口,并且所有可滚动的盒应该假设滚动到其起点。
决定这些元素的应用值的约束是:left + margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right + right = 包含块的宽度。
序号 |
left |
width |
right |
结果 |
1 |
auto |
auto |
auto |
把所有值为auto的margin-left和margin-right设为0,。然后如果建立静态位置包含块的元素的direction为ltr,吧left设置为静态位置并应用规则5,否则把right设置为静态位置并应用规则2。 |
2 |
auto |
auto |
非auto |
宽度自适应,再求出left |
3 |
auto |
非auto |
auto |
如果建立静态位置包含块的元素的direction属性是ltr,就把left设置为静态位置,否则把right设置为静态位置。然后求出left(如果direction为rtl)或者right(如果direction为ltr)。 |
4 |
auto |
非auto |
非auto |
求出left。 |
5 |
非auto |
auto |
auto |
宽度自适应,再求出right。 |
6 |
非auto |
auto |
非auto |
求出width。 |
7 |
非auto |
非auto |
auto |
求出right。 |
8 |
非auto |
非auto |
非auto |
如果margin-left和margin-right都是auto,解方程时要添加上额外的两个约束:2个margin的值相等,除非这会让它们为负。这种情况下,如果包含块的direction是ltr(或rtl),吧margin-left(或margin-right)设置为0,在求出margin-right(或margin-left)。 如果margin-left或者margin-right有一个是auto,就解方程求这个值。如果该值被过度限制了,就忽略left(如果包含块的direction为rtl,则是right)的值,再求出这个值。否则,把值为auto的margin-left和margin-right设置为0,再在上面2~7这6条规则中挑1条合适的应用。 |
自适应宽度的计算见浮动的非替换元素。
绝对定位的替换元素
这里绝对定位的非替换元素的约束方程仍然适用。
width的应用值由行内替换元素决定。如果margin-left或margin-right被指定为auto,其应用值由下面的规则决定:
- 如果left和right值都是auto,然后如果建立静态位置包含块的元素的direction为ltr,把left设置为静态位置,否则如果direction为rtl,就把right设置为静态位置。
- 如果left和right其中一个为auto,把所有值为auto的margin-left或者margin-right替换为0。
- 如果此时margin-left和margin-right仍然都是auto,解方程时要添上额外的的约束:2个margin必须相等,除非这会让它们为负。这种情况下,如果包含块的direction是ltr(或rtl),则把margin-left(或margin-right)设置为0,再求出margin-right(或margin-left)。
- 如果此时只剩一个auto了,就解方程求出这个值。
- 如果此时该值被过渡限制了,当包含块的direction为rtl(或ltr)时,忽略left(或right),再求出这个值。
最小、最大宽度:min-width和max-width
暂略
内容高度:height属性
该属性指定了盒的内容高度(content height)。该属性不适用于非替换的行内元素。其取值含义如下:
- <length>:指定一个固定值。
- <percentage>:制定一个百分比高度。百分比参照生成盒的包含块的高度。如果包含块的高度没有显示指定(即去绝对内容高度),并且该元素不是绝对定位的,则计算值为auto。根元素上的百分比高度是相对于初始包含块的。注意:对于那些包含块基于一个块级元素的绝对定位元素,百分比根据这个元素的内边距框(padding box)的高度来计算。这与CSS1不同,(CSS1中)百分比总是根据父级元素的内容框(content box)来计算。
- auto:取决于其他属性的值。
注意,绝对定位元素的包含块的高度独立于该元素本身的大小,因此这种元素上的百分比高度都可以计算出来(can always be resolved)。然而,可能直到文档中在此之后的元素处理完毕后,才能获知该高度
计算height与margin
计算top、margin-top、height、margin-bottom和bottom的值,必须区分盒的种类。
行内非替换元素
height属性不可用。
内容区(content height)的高度应该基于字体,但本规范没有具体说明。
行内替换元素、常规流中的替换inline-block元素、常规流中的块级替换元素、浮动的替换元素
如果margin-top或margin-bottom为auto,其应用值为0。
对于height的计算值为auto的情况:
- 如果该元素具有固有高度,则height的应用值就是该固有高度。
- 如果该元素不具有固有高度,但width的计算值不为auto,且该元素具有固有比例,height的应用值为“宽度的应用值/固有比例”。
- 如果以上情况都不满足,则height的应用值必须设置为比例为2:!,高度不超过150px并且宽度不超过设备宽度的最大矩形的高度。
块级非替换元素
此处讨论的是两种情况:
- 常规流中的块级不可替换元素,overflow的计算值为visible。
- 常规流中的块级不可替换元素,overflow的计算值不为visible但已经传播到视口。
如果margin-top或margin-bottom为auto,则其应用值为0。
如果height为auto,高度取决于该元素是否含有块级子级以及是否具有padding或border。该元素的高度为从其内容上边界到下面第一个适用的(位置)的距离:
- 最后一个行框的下边界。
- 最后一个流内子级的下外边距边界,如果该子级的下外边距没有和该元素的下外边距合并的话。
- 最后一个流内子级的下边框边界,如果其(该流内子级)上外边距不与该元素的下外边距合并的话。
- 否则为0。
只考虑常规流中的子集(即浮动盒和绝对定位盒会被忽略,并且相对定位的盒不考虑其偏移)。注意子级盒可以是一个匿名块盒。
绝对定位的非替换元素
对于绝对定位的元素,垂直方向的应用值必须满足这样的约束:top + margin-top + border-top + padding-top + height + padding-bottom + border-bottom + margin-bottom + bottom = 包含块的高度。
序号 |
top |
height |
bottom |
结果 |
1 |
auto |
auto |
auto |
把top设置为静态位置,并应用规则5。 |
2 |
非auto |
高度由BFC中的auto高度决定,把值为auto的margin-top和margin-bottom设置为0,再求出top。 |
||
3 |
非auto |
auto |
把top设置为静态位置,把值为auto的margin-top和margin-bottom设置为0,再求出bottom。 |
|
4 |
非auto |
把值为auto的margin-top和margin-bottom设置为0,再求出top。 |
||
5 |
非auto |
auto |
auto |
高度由BFC中的auto高度决定,把值为auto的margin-top和margin-bottom设置为0,再求出bottom。 |
6 |
非auto |
把值为auto的margin-top和margin-bottom设置为0,再求出height。 |
||
7 |
非auto |
auto |
把值为auto的margin-top和margin-bottom设置为0,再求出bottom。 |
|
8 |
非auto |
如果margin-top和margin-bottom都是auto,解方程时要添加上额外的约束:2个margin相等;如果其中一个是auto,解方程求出该解;如果被过度约束了,就忽略bottom这个值。 |
绝对定位的替换元素
height的应用值由行内替换元素(的固有高度)决定,其他与上面的类似。(官网写得让人云里雾里的)
复杂情况
本节适用于:
- 常规流中的块级非替换元素,当overflow的计算值不为visible时(除了overflow值已经传播到了视口的情况)
- 非替换的inline-block元素
- 浮动的非替换元素
如果margin-top或者margin-bottom为auto,其应用值为0。如果height是auto,高度取决于该元素的后代,根据BFC中的auto高度。
对于inline-block元素,在计算行框时,使用外边距框。
BFC中的auto高度
特定情况下(绝对定位的非替换元素,以及上面的复杂情况),一个建立了BFC的元素的高度按照如下规则计算:
- 如果它只含有行内级子级,高度就是最高的行框的顶端与最低的行框的底端之间的距离。
- 如果它只含有块级子级,高度就是最高的块级子级盒的上外边距边界到最低的块级子级的下外边距边界之间的距离。
- 绝对定位的子级会被忽略,并且相对定位的盒不考虑其偏移。
- 如果元素含有任意下margin edge位于元素的下content edge下方的浮动的后代,那么高度增加至能包含这些后代。只考虑参与此BFC的浮动,例如,不考虑绝对定位的后代中的浮动或其他浮动。