html - block 格式化上下文、折叠边距和 float 容器

标签 html css css-float css-position haslayout

为了了解 block 格式化上下文的作用,我试图找出在创建 BFC 时发生了什么。

我从 Everything you Know about Clearfix is Wrong 中获取了以下演示:

.wrapper {
  width: 740px;
  background: #cccccc;
}
.leftSidebar {
  float: left;
  width: 200px;
}
.rightSidebar {
  float: right;
  width: 200px;
}
.mainContent {
  padding-right: 200px;
  padding-left: 200px;
}
.floatMe {
  float: left;
  background: teal;
  color: #fff;
}
<div class="wrapper">
  <div class="leftSidebar">
    <h2>Heading</h2>
    <pre>.leftSidebar {
  float:left;
  width:200px;
}</pre>
  </div>
  <div class="rightSidebar">
    <h2>Heading</h2>
    <pre>.rightSidebar {
  float:right;
  width:200px;
}</pre>
  </div>
  <div class="mainContent">
    <h2>Heading</h2>
    <pre>.mainContent {
  padding-right:200px;
  padding-left:200px;
}</pre>
    <div class="floatMe">
      <pre>.floatMe {
  float:left;
  background:teal;
  color:#fff;
}</pre>
    </div>
  </div>
</div>

根据那篇文章(强调我的):

In modern browsers:

All elements belong to the same block formatting context so adjacent margins collapse. The heading’s margin “sticks out” of the wrapper to butt against the p. Unlike in IE, it is that margin (not the one on the black box) that creates the gap above the wrapper.

我无法理解“同一 block 格式化上下文”指的是什么。我想知道为什么在没有 block 格式化上下文的情况下会产生如此奇怪的布局。

我试图通过在 CSS 中添加 * {border: 1px solid blue;} 来找出确切的布局,但是在这次更改之后整体布局发生了很大变化:现在它的行为就像 wrapper block 格式化上下文!

.wrapper {
  width: 740px;
  background: #cccccc;
}
.leftSidebar {
  float: left;
  width: 200px;
}
.rightSidebar {
  float: right;
  width: 200px;
}
.mainContent {
  padding-right: 200px;
  padding-left: 200px;
}
.floatMe {
  float: left;
  background: teal;
  color: #fff;
}
* {
  border: 1px solid blue;
}
<div class="wrapper">
  <div class="leftSidebar">
    <h2>Heading</h2>
    <pre>.leftSidebar {
  float:left;
  width:200px;
}</pre>
  </div>
  <div class="rightSidebar">
    <h2>Heading</h2>
    <pre>.rightSidebar {
  float:right;
  width:200px;
}</pre>
  </div>
  <div class="mainContent">
    <h2>Heading</h2>
    <pre>.mainContent {
  padding-right:200px;
  padding-left:200px;
}</pre>
    <div class="floatMe">
      <pre>.floatMe {
  float:left;
  background:teal;
  color:#fff;
}</pre>
    </div>
  </div>
</div>

请告诉我发生了什么。

最佳答案

好问题,让我思考了很多!

这里涉及到很多概念,所以我将一一介绍:

有问题的 IE:

this 中提到的任何内容如果您不必针对 IE7 或 IE8 兼容模式进行设计,那么有关 IE 的旧文章很容易被忽略。此行为是由于 IE7 内部使用的 hasLayout 属性造成的。

参见 this MSDN doc对于 IE7:

What is "HasLayout" and why is it important?

There are several bugs in Internet Explorer that can be worked around by forcing "a layout" (an IE internal data structure) on an element.

显然,这是一种非标准的解决方法,并且会带来很多不一致之处。阅读有关此内容的信息 here也是。


block 格式化上下文 (BFC):

摘自 this MDN doc :

A block formatting context is a part of a visual CSS rendering of a Web page. It is the region in which the layout of block boxes occurs and in which floats interact with each other.

BFC 对于 float 元素的定位和清除非常重要 - float 元素仅影响相同的 BFC。当你float一个元素,它被从流中取出并通过“ float ”重新插入。

请看下面的例子:

  1. wrapper 的内部是一个 BFC,其中一个 div 向左浮动,另一个向右浮动。

  2. float 元素被重新插入到 BFC 中,同时围绕非 float 元素进行渲染。

  3. 因为你没有clear在 BFC 中编辑 float ,wrapper高度将扩展到未 float 的元素的大小。

        body{
          margin: 0;
        }
        *{
          box-sizing: border-box;
        }
        .wrapper{
          border: 1px solid;
        }
        .wrapper > * {
          display: inline-block;
          border: 1px solid red;
          width: 33.33%;
          height: 100px;
        }
        .left{
          float: left;
        }
        .right{
          float: right;
        }
        .center{
          height: 50px;
        }
        <div class="wrapper">
          <div class="left">Left</div>
          <div class="center">Center</div>
          <div class="right">Right</div>
        </div>

  4. 看看当你 clear 时会发生什么BFC 中的 float - 现在高度将在 wrapper 中表现正常BFC.

        body{
          margin: 0;
        }
        *{
          box-sizing: border-box;
        }
        .wrapper{
          border: 1px solid;
        }
        .wrapper > * {
          display: inline-block;
          border: 1px solid red;
          width: 33.33%;
          height: 100px;
        }
        .left{
          float: left;
        }
        .right{
          float: right;
        }
        .center{
          height: 50px;
        }
        .wrapper:after{
          content: '';
          display: block;
          clear: both;
        }
        <div class="wrapper">
          <div class="left">Left</div>
          <div class="center">Center</div>
          <div class="right">Right</div>
        </div>


折叠边距:

Top and bottom margins of blocks are sometimes combined (collapsed) into a single margin whose size is the largest of the margins combined into it, a behavior known as margin collapsing.

相邻 block 父 block 和第一个/最后一个子 block 空 block 的边距折叠。在 this MDN doc 中查看更多关于 margin 崩溃的信息.

另请注意:

Margins of floating and absolutely positioned elements never collapse.



那么这里到底发生了什么?

  1. 现在您将了解 BFC 以及 float 容器在第一种情况下的工作方式(当您没有指定边界时)- 这就是为什么 floatMe远离它的直接mainContent包装器以及为什么 wrapper 的高度和 mainContent就像那里看起来的那样。

  2. LayoutIE 仅在 IE7 中提及,是非标准的。

  3. 发生的所有其他事情都是因为边距崩溃:

    一个。 h2pre边缘崩溃(相邻的 sibling )

    mainContent向顶部移动一点以折叠 body 上的边距( parent 和第一个/最后一个 child )

    作为wrapper高度为 mainContent , wrapper高度也向上移动。

    当你应用边框时会发生什么,上面 (b) 中的边距折叠被取消了! (请参阅上面的 MDN 文档了解原因)



希望现在情况好转了。干杯!

关于html - block 格式化上下文、折叠边距和 float 容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39920386/

相关文章:

html - 在页面左侧显示第一列的 4 行

html - 空白 :normal inside white-space:nowrap

css - div 不会 float ,任何人都可以看到为什么吗?

html - div 内表格 float 溢出

javascript - 查找动态生成表的表行索引

html - 表在 tr 中设置最大行数

html - 导航栏自动分成两行

css - 有没有办法在 Firefox 中平滑字体图标?

html - div 的文本内容没有 float 框

javascript - 复制到剪贴板按钮