块级元素宽度是其父元素宽度的100%,高度与内容高度一致。
内联元素的高度和宽度都与内容一致,
无法设置内联元素的宽度和高度,如果想控制内联元素的尺寸,需要设置元素的display属性值为block或者inline-block
正常布局流是一套在浏览器视口内放置、组织元素的规则。
默认的,块级元素按照其父元素的块流动方向 (block flow direction)放置:每个块级元素会在上一个元素下面另起的一行,它们会被设置好的外边距进行分隔。在水平书写模式下,块级元素垂直排列。
内联元素不会另起一行;只要其父块级元素的宽度空间足够,它们与其他内联元素、相邻的文本内容被排列在同一行上,如果宽度空间不够,溢出的文本或元素将移到新的一行。
If two vertically adjacent elements both have a margin set on them and their margins touch, the larger of the two margins remains and the smaller one disappears. This is known as margin collapsing. Collapsing margins is only relevant in the vertical direction. 【本段内容摘取自MDN官方文档:Normal Flow】
如果两个垂直相邻的元素都有外边距margin且相互接触,则大的margin继续存在,小的消失。这就是所谓的margin collapsing。margin collapsing只在垂直方向上有意义。
The top and bottom margins of blocks are sometimes combined (collapsed) into a single margin whose size is the largest of the individual margins (or just one of them, if they are equal), a behavior known as margin collapsing. 【本段内容摘取自MDN官方文档:Mastering margin collapsing】
块的顶部和底部外边距有时会合并(combined)或重叠(collapsed)为一个外边距,它是两个单独的外边距中较大的那个(如果边距相等,则是两个单独的外边距的任意一个),这种行为称为margin collapsing。
上文两段文字都是来自MDN官方文档关于margin collapsing的介绍,大致意思基本相同。我们做进一步总结:
margin collapsing:在垂直方向上,两个相互接触的外边距margin会合并为一个外边距,该外边距的尺寸与两个外边距中较大的保持一致。
margin collapsing的中文翻译不一,主要有外边距折叠、外边距重叠,外边距合并,外边距坍塌、外边距塌陷。在下文关于margin collapsing时,我会选择使用外边距合并一词。
注意,浮动和绝对定位元素之间不会发生外边距合并。
发生外边距合并的三种基本情况:
外边距合并的关键点是垂直方向和接触,这三种基本情况的外边距接触是如何发生的呢?
相邻的兄弟元素一个元素的顶部外边距和另一元素的底部外边距可能接触;父元素和子元素的顶部外边距或底部外边距可能接触;当个空的块级元素的上边距和下边距可能接触。
The margins of adjacent siblings are collapsed (except when the latter
sibling needs to be cleared past floats).
相邻的兄弟之间的外边距会被合并(除非当两个兄弟中的后者需要被清除之前的浮动,如此,两相邻兄弟之间的外边距不会被合并)
关键代码
HTML
<div class="container">
<div>div>
<div>div>
div>
CSS
.container {
border: 5px solid #000;
display: flow-root;
}
.container > div {
height: 100px;
background-color: red;
margin: 50px 0;
}
给父盒子设置黑色边框并通过display: flow-root;属性使得盒子形成BFC。给两个子div盒子同时设置外边距属性margin: 50px 0;,前面div盒子的margin-bottom和后面div盒子的margin-top发生合并。这种情况,应该是比较容易理解的。
渲染效果,如下图所示
查看完整代码

什么情况,相邻的兄弟不会发生外边距合并呢?
官方文档中的这句话给了我们答案:“except when the latter sibling needs to be cleared past floats” ,这句话的大概意思是“除非当两个兄弟中的后者需要被清除之前的浮动时”(如此,两相邻兄弟之间的外边距不会被合并)。
这句话,我当时读了不下十遍,并使用了各种翻译软件。原因是我个人翻译的中文依然无法理解什么意思,让我怀疑自己是不是翻译错了,结果软件和我本人的翻译差别不大。我自己是解决不了了,于是,只能上百度和google寻找答案,发现并没有对这句话做出过解释,更不用提对应的代码案例分析了。最后,我想到了stackoverflow(一个英文互联网问题问答网站,个人在此强烈推荐),终于没让我失望,它对这句话做了详细的解释。
下文内容参考自stackoverflow:Margin Collapse for Adjacent siblings
Temani Afif 关于 except when the latter sibling needs to be cleared past floats 的解答翻译如下
首先,下文中的案例只能在使用基于Gecko内核的浏览器(例如,Firefox)上运行。Chrome或者基于Webkit内核的浏览器具有错误地实现清除(注释:清除,clearance,指清除浮动)的悠久历史。
我 (Temani Afif )认为该语句“except when the latter sibling needs to be cleared past floats”是对规范的错误解释。规范实际上要表达的是
两个外边距是毗邻的(注释:毗邻和我上文中的接触意思相同)当且仅当:
两者属于标准流中同一BFC(block fomatting context,块级格式化上下文)块级盒子并且没有行盒(line boxes)、清除(clearance)、内边距(padding)、边框(border)分隔它们。
(注释1:clearance,直译是清除,个人总感觉这样翻译不好理解,如果你觉得容易理解,或者有更好的翻译,可以使用自己的翻译。或者直接使用clearance,不翻译更准确)
(注释2:本段的意思是,外边距合并的条件之一是接触,而接触的条件是两个外边距之间没有行盒,没有清除,没有内边距、没有边框。在相邻的兄弟元素之间,外边距接触的条件之包含没有清除。换句话说,如果外边距存在清除,则外边距不再接触,故也不会再合并 另外两种外边距合并基本情况:没有内容分隔的父元素和子元素和空的块(块级元素) ,外边距接触的条件包含没有行盒,没有清除,没有内边距、没有边框等等下文会详细介绍。)因此,这里什么情况会促使清除发挥作用(注释:发挥分隔两个margin的作用)呢?注意,它不是两元素中较后者兄弟元素的清除,而是两元素之间的元素的清除。(注释:感觉有点而绕,解释下,两个相邻的兄弟元素之间有一个元素,它没有任何内容,也没有高度,注意,这里两个元素中间虽然插入了一个元素,但是它没有内容,没有高度或高度为0,我们依然认为两个元素是相邻的兄弟元素。当中间元素的清除没有发挥作用时,那么两个兄第之间就认为没有分隔的,还是接触的,因此外边距会合并;当中间元素的清除发挥作用时,那么两个兄弟元素之间就认为时有分隔的,不接触的,因此外边距不会合并)
考虑以下案例
HTML<div class="container"> <span>span> <div>div> <b>b> <div>div> div>
- 1
- 2
- 3
- 4
- 5
- 6
CSS
.container { display: flow-root; border:5px solid black; } span { float:left; width:100px; height:100px; background-color: green; opacity:0.5; } .container > div { height:60px; margin:20px 0; background-color:red; } b { display:block; clear:left; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
给父盒子设置黑色边框并通过
display: flow-root;属性使得盒子形成BFC。span元素左浮动并设置宽width:100px;高height: 100px;div盒子的高度height: 60px;,外边距margin: 20px 0;, 对于b元素(display为block,表现和块级元素一致),通过设置属性clear: left清除左浮动,(如果你对清除浮动不太了解,可以阅读文章:CSS 清除浮动),根据官方定义,元素清除浮动后,会把元素移动到浮动元素的下面。但是这里上面的div盒子的高度时60px加上margin-top和margin-bottom,整体的高度为100px,和浮动元素的高度相同。这时候,放在标准流中的靠前的div盒子后面的b元素,本来就在浮动元素的小面,此时,清除没有发挥作用(no clearance)。由于前后两个div盒子是没有被清除分隔的,或者说是接触的,因此会发生外边距合并。
按规定,元素本身就在浮动元素的下面,那么清除浮动本应该不生效(no clearance),因为浮动的定义或者作用就是将元素移动到它之前的所有相关的浮动元素的下面。但是,上文也说了,Chrome和webkit内核的浏览器有错误地实现清除(注释:清除,clearance,指清除浮动)的悠久历史,即只要设置了清除浮动,即使该元素本身已经再浮动元素的下方,清除也生效(clearance)。
Firefox浏览器渲染效果,如下图所示(Firefox浏览器,元素高度为0,会显示一条虚线,Chrome浏览器不会显示)
查看完整代码,要想有下图效果,注意需要使用Firefox火狐浏览器
然而,在下面这个案例中
HTML代码同上
CSS代码,我们只是把div盒子高度从原来的60px修改为现在的59px.container > div { height:59px; margin:20px 0; background-color:red; }
- 1
- 2
- 3
- 4
- 5
此时,较前的div盒子的整体高度height + margin-top + margin-bottom = 99px,而浮动元素span的高度height为100px,放置在较前div盒子之后的b元素(display为block,相当于块级元素)清除浮动,它需要向下移动1px才能到浮动元素span的下方,因此清除有效。
Firefox浏览器渲染效果,如下图所示
查看完整代码,要想有下图效果,注意需要使用Firefox火狐浏览器。另外,可以把div盒子的高度调小些,例如50px,然后再注释掉b元素的clear: left属性,接着解除注释,能更直观的观察到发生清除的效果。
上面的两端代码在Chrome浏览器或者webkit内核的浏览器中运行,运行效果大致相同,只是一个div盒子高度59px,一个60px而已,因此下文使用一张图来说明这两种情况。不管元素b是否在浮动元素下方,只要设置了清除浮动
clear: left;,清除就一定生效。
If there is no border, padding, inline part, block formatting context created, or clearance to separate the margin-top of a block from the margin-top of one or more of its descendant blocks; or no border, padding, inline content, height, or min-height to separate the margin-bottom of a block from the margin-bottom of one or more of its descendant blocks, then those margins collapse. The collapsed margin ends up outside the parent.
如果没有边框、内边距、行级内容、被创建的BFC或清除来分隔父块元素和一个或多个后代子块元素的顶部外边距margin-top;或者如果没有边框、内边距、行级内容、设置高度或者最小高度来分隔父块元素和一个或多个后代子块元素的底部外边距margin-bottom,(没有东西分隔margin,换句话就,父元素和子元素的顶部或底部margin会接触),那么父子元素的外边距会合并。合并的边距最终在父元素之外。
关键代码
HTML
<div class="container">
<div>div>
div>
CSS
body {
border: 5px solid #000;
display: root-flow;
}
.container {
width: 150px;
height: 150px;
margin-top: 50px;
background-color: red;
}
.container > div {
width: 50px;
height: 50px;
background-color: green;
margin-top: 50px;
}
红色div父盒子和绿色div子盒子margin-top: 50px;,由于父子盒子之间的顶部外边距没有分隔,或者说存在接触,因此外边距发生合并。
查看完整代码

什么情况下,父子盒子的顶部外边距不会合并?
不让父子盒子的顶部外边距接触即可,父子元素之间可以存在以下东西
1、添加行级内容
所有行级内容,例如没有元素包裹的文本,行内元素span等等
基于完整代码做部分修改
HTML
<div class="container">
hello,html
<div>div>
div>

2、父盒子添加内边距
基于完整代码做部分修改
CSS
.container {
width: 150px;
height: 150px;
margin-top: 50px;
background-color: red;
padding-top: 50px;
}
渲染效果

3、父盒子创建BFC
常见的创建BFC的方法是给元素添加属性overflow: auto 或者 display: flow-root。如果对与BFC是什么,BFC如何创建等内容感兴趣,可以参考XXXX。关于BFC的内容,不是本文章的重点,且内容繁多,因此不再通过本文讲解。
基于完整代码做部分修改
CSS
.container {
width: 150px;
height: 150px;
margin-top: 50px;
background-color: red;在这里插入图片描述
display: flow-root;
}
渲染效果,如下图所示

4、存在清除或者清除有效
这部分代码相对之前的代码改动较多,所以不在基于原来的代码进行修改。可以查看清除完整代码
渲染效果如下图所示

如果把蓝色盒子(看图是紫色,给蓝色盒子设置了透明度,在红色背景下显示了紫色)设置左浮动,b元素设置清除浮动,b元素移动到浮动元素的下方,清除有效。
如果把浮动元素span的高度设置为0,b元素本身就在浮动元素的下面,因此不会清除。父元素和子元素之间没有分隔,所以父元素和子元素的顶部外边距会合并。
Firefox渲染效果如下图所示

Chrome 渲染效果如下图所示
清除只要设置就有效

上文介绍了顶部外边距发生合并或者不合并的场景。那么,底部外边距合并或者不合并的场景有哪些呢?
没有边框边框、内边距、行级内容会发生外边距合并,这些场景底部和顶部外边距的情况相同。除此之外,顶部外边距没有清楚,底部外边距没有设置高度也会合并。
5、父元素元素不设置高度
基于完整代码做部分修改
先来考虑设置高度的场景。
CSS
.container > div {
width: 50px;
height: 50px;
background-color: green;
margin-top: 50px;
margin-bottom: 150px;
}
给绿色子盒子添加底部外边距属性 margin-bottom: 150px
渲染效果如下图所示
由于父盒子设置了固定高度,那么子盒子超出父亲盒子的任何部分,包括内容、内边距、外边距都要发生溢出。溢出的内容不会对其他元素的布局产生影响。我们知道,外边距接触是合并的必要条件。我们设置绿色子盒子的底部外边距为100px,整好和父盒子的底部外边距接触,父盒子底部外边距为0px。合并后为100px且位于父元素的底部,这是矛盾就产生了?前提是设置了固定高度,当合并后的100px底部外边距位于父元素底部时,那子盒子下面的100px的外边距不就消失了吗?如果高度是可以自由调节的,那么,只要父盒子的高度和子盒子一致。那么,合并后的外边距,依然可以在子盒子下面出现。

当我们不设置父盒子的高度时,父盒子的高度由内容撑开。子盒子的底部外边距和父盒子的底部外边距合并。
CSS
.container {
width: 150px;
/* height: 150px; */
margin-top: 50px;
background-color: red;
}
删除父盒子的高度属性,子盒子外边距100px,父盒子外边距0px,合并后外边距100px,位于父盒子的下面
渲染图片,如下图所示

块级元素没有高度,没有任何内容
关键代码
HTML
<div class="container">
<div>div>
<div id="empty">div>
<div>div>
div>
CSS
.container {
border: 5px solid #000;
display: flow-root;
}
.container > div {
height: 100px;
background-color: red;
}
#empty {
height: 0;
margin: 50px 0;
}
上、中、下三个div盒子,中间的div盒子为空盒子(即下图中的虚线),设置顶部和底部外边距margin: 50px 0; 由于没有内容和高度,顶部和底部外边距产生接触,发生合并。
查看完整代码

Some things to note:
- More complex margin collapsing (of more than two margins) occurs when the above cases are combined.
- These rules apply even to margins that are zero, so the margin of a descendant ends up outside its parent (according to the rules above) whether or not the parent’s margin is zero.
- When negative margins are involved, the size of the collapsed margin is the sum of the largest positive margin and the smallest (most negative) negative margin.
- When all margins are negative, the size of the collapsed margin is the smallest (most negative) margin. This applies to both adjacent elements and nested elements.
- Collapsing margins is only relevant in the vertical direction.
需要注意的事情: