经典知识,学习细节。
box dimensions
css
为elements
生成box
,box
是由content
区域以及padding
border
margin
区域组成的,其中padding border margin
不一定每个box
都有。它们的包含关系如图所示:
每个box
最里面的矩形区域是content
,content
外面包裹的第一层环形矩形区域是padding
,padding
外面包裹的第一层环形矩形区域是border
,border
外面包裹的第一层环形矩形区域是margin
。
其它概念的含义如下:
content edge
指的是content
的矩形内容区域的四条边padding edge
指的是padding
区域外侧的四条边,当padding:0
的时候,padding edge
与content edge
重合border edge
指的是border
区域外侧的四条边,当border:none
的时候,border edge
与padding edge
重合margin edge
指的是margin
区域外侧的四条边,当margin:0
的时候,margin edge
与border edge
重合content box
就是content
padding box
指的是padding edge
包裹的矩形区域,等于content
+padding
border box
指的是border edge
包裹的矩形区域,等于content
+padding
+border
margin box
指的是margin edge
包裹的矩形区域,等于content
+padding
+border
+margin
content padding border margin
分上下左右四个部分,比如LM RM
分别指的是left margin
rigth margin
content edge, padding edge, border edge, margin edg
当然也分4条边。
box
的background
是在content border padding
这三个区域生效的,margin
区域的background
始终是透明的。
margin properties
与margin
有关的properties
一共有5个,用来定义margin
的大小。分别是:
margin-top
定义left margin
的大小margin-right
定义right margin
的大小margin-bottom
定义bottom margin
的大小margin-left
定义left margin
的大小margin
前面四个的简写,可按照top right bottom left
的顺序,在一个属性中一次性定义1-4个margin property
<margin-width>
以上5个属性,全部都依赖<margin-width>
这个value type
,它的定义如下:1
<margin-width> = <length> | <percentage> | auto
什么是value type
以及<length>
和<percentage
>这两个value type
在哪定义的,都可前往css-values这个文档学习。
简单来说,<length>
一般就是px em rem
这些值,属于绝对值,写多少就是多;<percentage>
是指百分比或浮点数作为值,属于相对值,它要依赖于box
所在的containing block
的width
来计算最终的margin
值。下面的值,都是合法的<margin-width>
:1
2
3margin: 20px;
margin: 20%;
margin: auto;
需要着重说明的是,上下左右四个margin
都可以设置<percentage>
的值,然后不管是谁,这个百分比值,都是相对于当前box
的containing block
的width
来计算的。比如:1
2
3<div style="width: 400px; height: 300px">
<div style="margin: 20%"></div>
</div>
上面这个例子中,最终内层div
上下左右的margin
值就是: 20% * 400px = 80px
,不能想当然的认为左右margin
是根据containing block width
计算,而上下margin
是根据containing block height
计算。
另外,百分比单位是相对containing block
的width
计算的,如果containing block
的宽度是由当前box
撑起来的话,那么当前box
的百分比值计算出来就是undefined
。上面的例子之所以百分比单位有效,是因为第一层div的width是明确指定的,不是靠第二层div的box
填充起来的。这个要点可以帮助你分析某些时候为什么百分比单位会无效。
auto
需要前往其它内容学习,才能知道它的计算方式。另外margin
值还能设置负的值,也就是负的<length>
是允许的。这两个要点需要学习其它内容才能明确。
margin-top margin-bottom
这两个property的定义
定义:
<margin-width> | inherit
初始值: 0
应用于: 除了table display types
以外的所有元素,table-caption, table, inline-table
这3个table display type
的元素可以使用margin
是否可被继承: no
百分比计算: 相对containing block
的width
来计算
这两个属性定义垂直方向的margin
,它们对display: inlne
的non replaced elements
无效。
margin-left margin-rigth
这两个property的定义
定义:
<margin-width> | inherit
初始值: 0
应用于: 除了table display types
以外的所有元素,但是table-caption, table, inline-table
这3个table display type
的元素可以使用margin
是否可被继承: no
百分比计算: 相对containing block
的width
来计算
这两个属性定义水平方向的margin。
margin
的定义
定义:
<margin-width>{1,4} | inherit
初始值: 参考各个单独的属性定义
应用于: 除了table display types
以外的所有元素,但是table-caption, table, inline-table
这3个table display type
的元素可以使用margin
是否可被继承: no
百分比计算: 参考各个单独的属性定义
这个属性可以一次性定义4个方向的margin
,遵循上右下左的顺序。<margin-width>{1,4}
代表<margin-width>
可以重复1到4次。
Collapsing margins 外边距合并
首先只有垂直外边距才会合并,水平外边距始终不会发生合并,所以谈论外边距合并,说的仅仅是垂直外边距。在css
里面,相邻的垂直外边距会发生合并,从两个外边距合并成一个,合并完那个外边距又称为collapsed margin
。
有两个场景即使满足外边距合并的条件也一定不会合并:
root elment
的margin
不会合并,root element
是html
这个元素- 如果一个有
clearance
的box
上下外边距相邻,那这个box
会与它后面相邻的其它box
的margin
发生合并,但是它们合并的最终collapsed margin
,不会再与parent box
的margin-bottom
发生合并。
第二种情况举例如下:1
2
3
4
5
6
7<div style="border: 1px solid #ccc;width: 500px; margin: 0 auto;">
<div class="container" style="margin: 10px 0;background-color: rebeccapurple;">
<div style="float:left;width: 50px; height: 50px; background-color: #ccc;"></div>
<div class="clearance" style="margin: 30px 0;clear: both;height:0;"></div>
<div class="sibling" style="margin: 30px auto;height:0;"></div>
</div>
</div>
效果如下:
在这个例子中,div.container
是parent box
,而div.clearance
是一个有设置清除浮动的box
(清除浮动会导致该box的margin top
上方增加clearance
),且上下边距相邻,它会自身进行margin合并,然后再与div.sibling
的box
发生合并,但是它们俩合并完之后的margin
并没有跟div.container
的margin-bottom: 10px
发生合并,不然从上面的效果图中看到的边框距离颜色内容区域的距离,就不会是那么点距离。
外边距合并的条件为:
- 要被合并的外边距对应的
box
,不能脱离普通文档流,且它们的box
必须位于同一个block formatting context
当中 - 不能有
line box
(行框)、padding
、border
以及clearance
在两个外边距之间,否则它们不会合并
有以下几种外边距合并的形式:
parent box
的top margin
与它第一个child box
的top margin
发生合并box
的bottom margin
会和它相邻的下一个元素的box
的top margin
发生合并parent box
的bottom margin
与它最后一个chilld box
的bottom margin
发生合并- 同一个
box
的top margin
和bottom margin
在min-height
为0、height
为0或者是auto
、并且没有content
的时候,也会发生合并;说白了同一个box
发生合并,则它的border box
高度必须为0,不然top margin
跟bottom margin
碰不到
外边距是两两合并,然后得到一个新的外边距,新的外边距如果与其它box的外边距继续满足合并条件则还会发生合并;通过上面的合并形式,可以看到,外边距可以发生在父子元素之间、相邻元素之间、元素自身,所有在满足条件的情况下,一次完整的外边距合并,可能包含多个box
,而且会跨越box tree
多层结构。
另外一种合并形式总结:
- Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
- Margins of elements that establish new block formatting contexts (such as floats and elements with ‘overflow’ other than ‘visible’) do not collapse with their in-flow children.
- Margins of absolutely positioned boxes do not collapse (not even with their in-flow children).
- Margins of inline-block boxes do not collapse (not even with their in-flow children).
上面这4条英文规范的说的是同一个情况,就是外边距只能在同一个BFC
中发生,当两个外边距相邻,但是属于两个不同的BFC
,则不会发生合并- The bottom margin of an in-flow block-level element always collapses with the top margin of its next in-flow block-level sibling, unless that sibling has clearance.
文档流中block-level
元素的bottom margin
始终会跟文档流中下一个block-level
元素的top margin
发生合并,除非下一个元素通过清除浮动产生了clearance
- The top margin of an in-flow block element collapses with its first in-flow block-level child’s top margin if the element has no top border, no top padding, and the child has no clearance.
文档流中的block-level
元素的top margin
会跟它第一个在文档流中的block-level
子元素的top margin
发生合并,前提是这个父元素没有设置top border
、没有设置top padding
、且子元素没有通过清除浮动产生clearance
。- The bottom margin of an in-flow block box with a ‘height’ of ‘auto’ and a ‘min-height’ of zero collapses with its last in-flow block-level child’s bottom margin if the box has no bottom padding and no bottom border and the child’s bottom margin does not collapse with a top margin that has clearance.
文档流中block-level
元素的bottom margin
,会跟它最后一个在文档流中的block-level
子元素的bottom margin
发生合并,前提是这个父元素自己没有设置bottom padding
、没有设置bottom border
、并且这个子元素的bottom margin
没有跟它之前的有clearance
的top margin
合并过。 同时父元素如果设置非0的height
或min-height
,也可能会导致前面的情况无法合并,因为height
或min-height
可能会导致最后一个在文档流中的block-level
子元素的bottom margin
接触不到parent box
的bottom margin
。- A box’s own margins collapse if the ‘min-height’ property is zero, and it has neither top or bottom borders nor top or bottom padding, and it has a ‘height’ of either 0 or ‘auto’, and it does not contain a line box, and all of its in-flow children’s margins (if any) collapse.
一个元素的上下边距发生合并,前提是:它的min-height
是0、且它没有设置上下的border or padding
、且它的height
是0 or auto
、且它里面没有line box
、如果有children
则children
也必须全都自身发生了合并。
要点
前面介绍的外边距合并相当复杂,总结几个要点如下:
root elemennt
的margin
不会合并- 外边距合并只发生在同一个
BFC
当中 - 两个要合并的外边距之间如果有
line box
或padding
或border
或clearance
,则不会合并 - 外边距有4种合并情况:第一,
parent
的top margin
与第一个child
的top margin
合并;第二,box
的bottom margin
与相邻的下一个box
的top margin
合并;第三,parent
的bottom margin
与最后一个child
的bottom margin
合并;第四,同一个box
的上下外边距发生合并。
外边距合并的计算逻辑:
如果要合并的外边距都是正的,就取它们的最大值。如果里面有负的外边距,就先取所有正的外边距的最大值,然后减去所有负的外边距的绝对值的最大值。如果都是负的,就是0减去所有外边距的绝对值的最大值。
padding properties
与padding
有关的properties
一共有5个,用来定义padding
的大小。分别是:
padding-top
定义left padding
的大小padding-right
定义right padding
的大小padding-bottom
定义bottom padding
的大小padding-left
定义left padding
的大小padding
前面四个的简写,可按照top right bottom left
的顺序,在一个属性中一次性定义1-4个padding property
<padding-width>
以上5个属性,全部都依赖<padding-width>
这个value type
,它的定义如下:1
<padding-width> = <length> | <percentage> | auto
下面的值,都是合法的<padding-width>
:1
2
3padding: 20px;
padding: 20%;
padding: auto;
跟margin
一样,上下左右四个padding
都可以设置<percentage>
的值,然后不管是谁,这个百分比值,都是相对于当前box
的containing block
的width
来计算的。 containing block
有一个专门的定义,在后面讲position的博客中会专门介绍。
padding
值不能设置负的值。
padding-top pading-bottom padding-left padding-right
的定义
定义:
<padding-width> | inherit
初始值: 0
应用于: 除了display
为table-row-group, table-header-group, table-footer-group, table-row, table-column-group and table-column
的所有元素
是否可被继承: no
百分比计算: 相对containing block
的width
来计算
padding
的定义
定义:
<padding-width>{1,4} | inherit
初始值: 参考各个单独的属性定义
应用于: 除了display
为table-row-group, table-header-group, table-footer-group, table-row, table-column-group and table-column
的所有元素
是否可被继承: no
百分比计算: 参考各个单独的属性定义
这个属性可以一次性定义4个方向的padding
,遵循上右下左的顺序。<padding-width>{1,4}
代表<padding-width>
可以重复1到4次。
border properties
这个就比较简单了, 参考各种教程学习都行。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23border
border-top
border-left
border-right
border-bottom
border-color
border-top-color
border-right-color
border-bottom-color
border-left-color
border-width
border-left-width
border-right-width
border-top-width
border-bottom-width
border-style
border-top-style
border-bottom-style
border-left-style
border-right-style
一共有以上这么多个border
属性。