关于BFC的特征,为什么说内部的box会在垂直方向一个接一个放置?

BFC的特征有以下两点:

  • 内部的Box会在垂直方向,一个接一个地放置。

  • 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。

这两点我十分不明白,为什么说内部的box会在垂直方向上一个一个放置,这不是只有内部box都是块级元素的情况下才会出现的吗?如果元素是行内级元素或者浮动元素,不就不会这样了吗?

第二点也是同理,为什么说每个元素的margin box的左边都会与包含块border box的左边相接触?即使浮动也是如此?可是如果浮动或者行内级,第二个元素的margin不会与包含块边缘接触呀?

而且,哪怕接触,也应该适合包含块的content box相接触吧,为什么会是border box呢?

(为了方便浏览把疑惑的问题加粗了,不是为了博存在感,请见谅~)

阅读 5.8k
2 个回答

关于第一点:这个我现在还不太清楚。等看完W3C文档仔细研究一下再回答

关于第二点:你要先理解包含块的概念。包含块不是一个完整的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。而不是content-box。

又例如:某个盒子 position 属性是 static 或 relative 的话,包含块就是由它的最近的祖先块元素的content-box的边缘组成的。
简单的说,默认定位的盒子,其包含块就是块级父元素的content-box

再例如,position 为 fixed 盒子的包含块为视口,
简单的说,固定定位盒子你怎么滚动始终在所看到的窗口上。

有了包含块的概念,再回过头去看规范中的关于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 正确的翻译为左边缘。

看代码理解:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .bfc {
            width: 500px;
            height: 500px;
            padding-left: 50px;
            border: 2px solid #333;
            background-color: #afafaf;
            position: absolute;
        }
        .bfc div {
            width: 200px;
            height: 100px;
        }
        .sub-float {       
            background-color: seagreen;      
            float: left;
        }
        .sub-fixed {
            background-color: deepskyblue;
            position: fixed;
            right: 0px;
            top: 0px;     
        }
        .sub-absolute {
            background-color: deeppink;
            position: absolute;
            right: 0px;
            bottom: 0px;     
        }
    </style>
</head>
<body>
    <div class="bfc">
        <div class="sub-float"></div>
        <div class="sub-absolute"></div>
        <div class="sub-fixed"></div>
    </div>
</body>
</html>

效果图:
clipboard.png

div.bfc使用position:abosulute形成了一个bfc。它有三个子盒子。一个浮动,一个绝对定位,一个固定定位。

浮动盒子的定位属性为默认的static,因此其包含块为最近的块级祖先元素的content-box。正好就是bfc父盒子的内容区,因此按照规范,与bfc的content-box的左边缘接触,没毛病。

绝对定位盒子,其包含块为使用最近的使用了定位的祖先元素的padding-box,同样也是bfc盒子的,但这次指的是padding区域。于是先与bfc盒子的padding-box左边缘接触(也就是bfc盒子border-left的右边),当然,定位属性还有自身的规范,必须按照定位属性top left right bottom等找到自己位置。

固定定位盒子,其包含块为视口,同理与视口左边缘接触,再按照另行的规范,定位找到自己位置。没毛病。这个例子说明了,盒子的包含块,有可能与bfc盒子没半毛钱关系。

第二句翻译:即使存在浮动盒子也应该如此(如此的意思就是布局应该按照上述的规则进行),除非子盒子又形成了一个新的bfc。

这句话正确的理解方式为,一个bfc中,如果存在一个浮动的盒子,而其他盒子并没有形成新的bfc,那么所有的子盒子都应该触碰到其包含块的左边缘。举个例子,一个父盒子使用overflow:hidden形成bfc,其中有个子盒子,一个浮动,另一个不浮动。那么浮动盒子会盖住不浮动盒子,但是两个盒子都会触碰到bfc的content-box。这个你很容易理解对吧。

如果有两个浮动的盒子,也就是你的问题所在,第二个盒子会追在第一个盒子屁股后面,是不是违反规范了?你太年轻了,第二句话不说的很明白了吗。除非盒子自身又形成了一个新的bfc,第二个盒子使用浮动,不就形成了一个新的bfc了吗。

推荐问题
宣传栏