9.4 Normal flow
Boxes in the normal flow belong to a formatting context, which may be block or inline, but not both simultaneously. Block-level boxes participate in a block formatting context. Inline-level boxes participate in an inline formatting context.
float
除 none
以外的值;position
为absolute
,fixed
;display
为 inline-block
,table-cell
,table-caption
其中之一;overflow
为hidden
,auto
,scroll
;9.4.1 Block formatting contexts
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with ‘overflow’ other than ‘visible’ (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
margin
决定,属于同一个BFC的两个相邻的块级元素会发生margin
合并,不属于同一个BFC的两个相邻的块级元素不会发生margin
合并;float box
重叠;In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the ‘margin’ properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.
In a block formatting context, each box’s left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box’s line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).
对这几个特性解释一下:
1)内部的盒子(Box)会在垂直方向上一个接一个的放置:还没有理解,以后补充;
2)垂直方向上的距离由margin
决定,属于同一个BFC的两个相邻的块级元素会发生margin
合并,不属于同一个BFC的两个相邻的块级元素不会发生margin
合并
看一个例子:例1
//CSS
#div1 {
border: 1px solid #000099;
height: 60px;
width: 200px;
margin-bottom:20px;
background: red;
}
#div2 {
border: 1px solid #000099;
height: 60px;
width: 200px;
margin-top: 30px;
background: blue;
}
//HTML
#div1
和#div2
属于同一个BFC(body),因此发生了margin
折叠,基于此,取消折叠也很简单,可以让他们属于不同的BFC:例2
//HTML
<body>
<div id='par-div'><div id='div1'>div>div>
<div id='div2'>div>
body>
//CSS
#par-div {
overflow: hidden; //也可以使用其他的方式,依需求而定
}
3)每个盒子的左边,与包含块的左边相接触(从右往左的格式,右边缘接触)。即使存在浮动也是如此,除非产生了新的BFC;
可以参考https://segmentfault.com/q/1010000008875016,解释的很好。
要先理解包含块的概念。包含块不是一个完整的box,一个完整的box包含margin-box
,border-box
,padding-box
,content-box
。即使设置为0,也是存在的。
包含块有可能是某个盒子的content-box
,也有是某个盒子的padding-box
。这取决于被包含块所包含的盒子的position
属性。
例如:如果某个盒子 position
属性是 absolute
的话,包含块就由盒子最近的祖先元素(position
的值不是 static
(fixed
, absolute
, relative
, or sticky
))的padding-box
组成。简单的说,就是当使用子绝父相定位的时候,位置是相对于包含块而言的,也就是父元素的padding-box
。
又例如:某个盒子 position
属性是 static
或 relative
的话,包含块就由它的最近的祖先块元素的content-box
的边缘组成的。简单的说,默认定位的盒子,其包含块就是块级父元素的content-box
再例如,position
为 fixed
盒子的包含块为视口。简单的说,固定定位盒子你怎么滚动始终在所看到的窗口上。w3c原文描述:
10.1 Definition of “containing block”
The position and size of an element’s box(es) are sometimes calculated relative to a certain rectangle, called the containing block of the element. The containing block of an element is defined as follows:
(1)The containing block in which the root element lives is a rectangle called the initial containing block. For continuous media, it has the dimensions of the viewport and is anchored at the canvas origin; it is the page area for paged media. The ‘direction’ property of the initial containing block is the same as for the root element.
(2)For other elements, if the element’s position is ‘relative’ or ‘static’, the containing block is formed by the content edge of the nearest ancestor box that is a block container or which establishes a formatting context.
(3)If the element has ‘position: fixed’, the containing block is established by the viewport in the case of continuous media or the page area in the case of paged media.
(4)If the element has ‘position: absolute’, the containing block is established by the nearest ancestor with a ‘position’ of ‘absolute’, ‘relative’ or ‘fixed’, in the following way:
1)In the case that the ancestor is an inline element, the containing block is the bounding box around the padding boxes of the first and the last inline boxes generated for that element. In CSS 2.2, if the inline element is split across multiple lines, the containing block is undefined.
2)Otherwise, the containing block is formed by the padding edge of the ancestor.
If there is no such ancestor, the containing block is the initial containing block.
有了包含块的概念,再回过头去看w3c中的关于BFC的英文原文。
In a block formatting context, each box’s left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box’s line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).
原文第一句翻译,在一个bfc中,每一个盒子的左外边距应该和包含块的左边接触。这句话有两个地方值得注意
第一、 bfc中的盒子应该与其自身的包含块相接触,而非与bfc盒子相接触,这个包含块有可能是bfc中的一部分,也有可能和bfc无关。
第二、bfc中的盒子是与其包含块的 left edge 相接触,而不是包含块的left-border
相接触。因为包含块并非一个完整的盒子,不可能有left-border
。 left edge 正确的翻译为左边缘。
第二句翻译:即使存在浮动盒子也应该如此(如此的意思就是布局应该按照上述的规则进行),除非子盒子又形成了一个新的bfc。
这句话正确的理解方式为,一个bfc中,如果存在一个浮动的盒子,而其他盒子并没有形成新的bfc,那么所有的子盒子都应该触碰到其包含块的左边缘。举个例子,一个父盒子使用overflow:hidden
形成bfc,其中有个子盒子,一个浮动,另一个不浮动。那么浮动盒子会盖住不浮动盒子,但是两个盒子都会触碰到bfc的content-box。例3:
//css
#div1 {
float: left;
height: 60px;
width: 100px;
background: red;
}
#div2 {
height: 160px;
width: 200px;
background: blue;
}
//HTML
<body>
<div id='div1'>我是第一个div>
<div id='div2'>我是第二个div>
body>
如果BFC里有两个浮动的盒子,第二个盒子会追在第一个盒子屁股后面,是不是违反规范了?答案是没有,第二句话说的很明白,除非盒子自身又形成了一个新的bfc,第二个盒子使用浮动,不就形成了一个新的bfc了吗。还是上面那个例子,将#div2
形成BFC:例4
//css
#div2 {
float: left;
height: 160px;
width: 200px;
background: blue;
}
4)BFC的区域不会与float box重叠;
指的是,BFC盒子内部的区域,也就是BFC盒子的子元素,不会影响到float box元素及其内部子元素,并不是指BFC盒子本身
例5
//css
#div1 {
float: left;
height: 60px;
width: 100px;
background: red;
}
#div2 {
overflow: hidden;
height: 160px;
width: 200px;
background: blue;
}
//html
<div id='div1'>
<p>我是第一个p>
div>
<div id='div2'>我是第二个div>
//css
#div1 {
float: left;
height: 60px;
width: 100px;
background: red;
}
#div2 {
position: absolute;
height: 60px;
width: 35px;
background: blue;
}
//html
<div id='div1'>
<p>我是第一个p>
div>
<div id='div2'>我是第二个div>
6)计算BFC的高度时,浮动元素也参与计算。
我们知道,若父元素没有设置高度,当子元素float时,父元素不会被撑开:例6
//css
img {
float: right;
}
div {
border: 1px solid;
}
<p>在下面的段落中,添加了 <b>float:rightb> 的图片。导致图片将会浮动在段落的右边。p>
<div>
<img src="/attachments/cover/cover_css.png" width="95" height="84" />
<p>这是一些文本。这是一些文本。这是一些文本。p>
div>
因此可以利用BFC的这个特性,为父元素设置overflow:hidden
,代码如下:
//css
div {
border: 1px solid;
/* 具体使用哪个要看界面设计的情况 */
/* overflow: hidden; */
/* display:inline-block; */
/* position:absolute; */
overflow: hidden;
}
1、清除浮动,比如设置了overflow:hidden;、position:absolute;、float:left;
的元素,【其内部】的浮动会被清除(注意清除浮动说的都是float产生的浮动,position:absolute|fixed
那不叫浮动)
2、修复margin
折叠
3、两栏布局自适应,仅overflow+float
有效
参考资料
[1] https://www.w3.org/TR/CSS21/visuren.html
[2] https://segmentfault.com/q/1010000008875016
[3] https://www.jianshu.com/p/7e04ed3f4bea