理解 CSS 布局和 BFC

译者:前端小智css

原文:www.smashingmagazine.com/2017/12/und…html

CSS布局中有一些概念,一旦你理解了它们,就能真正提升你的 CSS 布局能力。本文是关于块格式化上下文(BFC)的。你可能从未据说过这个术语,可是若是你曾经用CSS作过布局,你可能知道它是什么,理解什么是 BFC,怎么工做以及如何建立 BFC 很是有用,这些能够帮助你理解CSS中的布局是如何工做的。前端

在本文中,经过熟悉的示例来解释什么是 BFC。而后说明 display 的一个新值,只有当你理解了什么是 BFC 以及为何须要它时,它才有意义。git

想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!github

什么是 BFC

在一个Web页面的CSS渲染中,块级格式化上下文 (Block Formatting Context)是按照块级盒子布局的。W3C对BFC的定义以下:浏览器

浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容建立新的BFC(块级格式上下文)。安全

BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,而且在一个 BFC 中,块盒与行盒(行盒由一行中全部的内联元素所组成)都会垂直的沿着其父元素的边框排列。ide

块格式化上下文(BFC)的行为经过一个简单的float示例很容易理解。在下面的示例中,我有一个框,其中包含向左浮动的图像和一些文本。若是咱们有足够多的文本,它会环绕浮动的图像和边框,而后环绕整个区域。布局

// html
<div class="outer">
  <div class="float">I am a floated element.</div>
  I am text inside the outer box.
</div>

// css
.outer {
  border: 5px dotted rgb(214,129,137);
  border-radius: 5px;
  width: 450px;
  padding: 10px;
  margin-bottom: 40px;
}

.float {
  padding: 10px;
  border: 5px solid rgba(214,129,137,.4);
  border-radius: 5px;
  background-color: rgba(233,78,119,.4);
  color: #fff;
  float: left;  
  width: 200px;
  margin: 0 20px 0 0;
}
复制代码

图片描述

若是我删除了一些文本,那么就没有足够的内容来包围图像,并且因为浮动被从文档流中脱离,因此边框会上升,并在图像下方,直到文本的高度。学习

图片描述

这是由于当咱们浮动一个元素时,文本所在的框的宽度保持不变,为给浮动元素腾出空间而缩短的是文本的行框。这就是为何背景和边框会出如今浮动后面的缘由。

咱们一般有两种方法来解决这个布局问题。一种方法是使用 clearfix hack,它的做用是在文本和图像下面插入一个元素,并将其设置为 clear:both。另外一种方法是使用 overflow 属性,其值不是缺省值 visible

.outer {
  overflow: auto;
}
复制代码

图片描述

查看演示

overflow 以这种方式工做的缘由是,使用 visible 的初值之外的任何值都会建立一个块格式化上下文,而 BFC 的一个特性是它包含浮动。

BFC 是布局中的一个迷你布局

你能够将 BFC 看做是页面内的一个迷你布局。一旦一个元素建立了一个 BFC,它就包含了全部的内容。正如咱们所看到的,这包括浮动的元素,它们再也不从盒子底部伸出来。BFC 还会致使一些其余有用的行为。

BFC 能够防止 margin 折叠

了解边距合并是另外一个被低估的 CSS 技能。在下一个示例中,假设有一个背景颜色为灰色的 div

这个 div 包含两个标签 p。外部 div 元素的 margin-bottom 为 40 像素,标签 p 的顶部和底部 margin 都是 20 像素。

// html
<div class="outer">
  <p>I am paragraph one and I have a margin top and bottom of 20px;</p>
  <p>I am paragraph one and I have a margin top and bottom of 20px;</p>
</div>
  
// css
.outer {
   background-color: #ccc;
  margin: 0 0 40px 0;
}

p {
  padding: 0;
  margin: 20px 0 20px 0;
  background-color: rgb(233,78,119);
  color: #fff;
}
复制代码

由于 p 元素的 margin 和外部 div 上的 margin 之间没有任何东西,因此两个会折叠,所以 p 最终与 div 的顶部和底部齐平。 咱们在 p 的上方和下方看不到任何灰色。

图片描述

在CSS当中,相邻的两个盒子(多是兄弟关系也多是祖先关系)的外边距能够结合成一个单独的外边距。这种合并外边距的方式被称为折叠,而且于是所结合成的外边距称为折叠外边距。折叠的结果按照以下规则计算:

  1. 两个相邻的外边距都是正数时,折叠结果是它们二者之间较大的值。
  2. 两个相邻的外边距都是负数时,折叠结果是二者绝对值的较大值。
  3. 两个外边距一正一负时,折叠结果是二者的相加的和。

产生折叠的必备条件:margin必须是邻接的!

若是咱们把盒子设为 BFC,它如今包含了标签 p 和它们的边距,这样它们就不会折叠,咱们能够看到边距后面容器的灰色背景。

.outer {
  background-color: #ccc;
  margin: 0 0 40px 0;
  overflow: auto;
}
复制代码

图片描述

查看演示

再一次,BFC 的工做是把东西装在盒子里,防止它们从盒子里跑出来。

BFC 能够阻止元素被浮动元素覆盖

你将熟悉 BFC 的这种行为,由于使用浮动的任何列类型布局都是这样工做的。若是一个项目建立了一个 BFC,那么该项目将不会包裹任何浮动元素。在下面的例子中,有以下 html 结构:

<div class="outer">
  <div class="float">I am a floated element.</div>
  <div class="text">I am text</div>
</div>
复制代码

带有 float 类的项被向左浮动,所以 div 中的文本在它环绕 float 以后。

图片描述

我能够经过将包裹文本的 div 设置为 BFC 来防止这种包裹行为。

.text {
  overflow: auto;
}
复制代码

图片描述

这其实是咱们建立具备多个列的浮动布局的方法。浮动项还为该项建立了一个 BFC,所以,若是右边的列比左边的列高,那么咱们的列就不会相互环绕。

查看演示

在多列布局中使用 BFC

若是咱们建立一个占满整个容器宽度的多列布局,在某些浏览器中最后一列有时候会掉到下一行。这多是由于浏览器四舍五入了列宽从而全部列的总宽度会超出容器。但若是咱们在多列布局中的最后一列里建立一个新的BFC,它将老是占据其余列先占位完毕后剩下的空间。

例如:

<div class="container">
    <div class="column">column 1</div>
    <div class="column">column 2</div>
    <div class="column">column 3</div>
</div>
复制代码

对应的CSS:

.column {
    width: 31.33%;
    background-color: green;
    float: left;
    margin: 0 1%;
}
.column:last-child {
  float: none;
}
复制代码

未建立 BFC 以前:

clipboard.png

添加如下样式建立一个 BFC:

.column:last-child {
  float: none;
  overflow: hidden; 
}
复制代码

clipboard.png

如今尽管盒子的宽度稍有改变,但布局不会打破。固然,对多列布局来讲这不必定是个好办法,但能避免最后一列下掉。这个问题上弹性盒或许是个更好的解决方案,但这个办法能够用来讲明元素在这些环境下的行为。

还有什么能建立 BFC?

除了使用 overflow 建立 BFC 外,其余一些 CSS 属性还建立 BFC。正如咱们所看到的,浮动元素建立了 BFC。你的浮动项将包含它里面的任何东西。

使用如下方式都能建立 BFC

  • float 的值不是 none。
  • position 的值不是 static 或者 relative。
  • display 的值是 inline-block、table-cell、flex、table-caption 或者inline-flex
  • overflow 的值不是 visible

建立 BFC 的新方式

使用overflow或其余的方法建立BFC时会有两个问题。首先,这些方法自己是有自身的设计目的,因此在使用它们建立BFC时可能会产生反作用。例如,使用overflow建立BFC后在某些状况下可能会看到出现一个滚动条或者元素内容被裁切。

这是因为overflow属性的设计是用来让你告诉浏览器如何定义元素的溢出状态的。浏览器执行了它最基本的定义。

即便在没有任何不想要的反作用的状况下,使用 overflow 也可能会让其余开发人员感到困惑。为何 overflow 设置为 autoscroll?最初的开发者的意图是什么?他们想要这个组件上的滚动条吗?

最安全的作法应该是建立一个 BFC 时并不会带来任何反作用,它内部的元素都安全的呆在这个迷你布局中,这种方法不会引发任何意想不到的问题,也能够理解开发者的意图。CSS 工做组也十分认同这种想法,因此他们定制了一个新的属性值:display:flow-root

flow-root 浏览器支持状况

你可使用display:flow-root安全的建立BFC,来解决上文中提到的各类问题:包裹浮动元素、阻止外边距叠加和阻止围绕浮动元素。

图片描述

浏览器对该属性的支持目前仍是有限的,若是你以为这个属性值很方便,请投票去让Edge也支持它。不过不管如何,你如今应该已经理解了什么是 BFC,以及如何使用 overflow 或其余方法来包裹浮动,以及知道了 BFC 能够阻止元素去环绕浮动元素,若是你想使用弹性或网格布局能够在一些不支持他们的浏览器中使用 BFC 的这些特性作降级处理。

理解浏览器如何布置网页是很是基础的。 虽然有时看起来可有可无,可是这些小知识能够加快建立和调试 CSS 布局所需的时间。

你的点赞是我持续分享好东西的动力,欢迎点赞!

交流

干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。

github.com/qq449245884…

我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,便可看到福利,你懂的。

相关文章
相关标签/搜索