企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] <br> <br> # BFC ## 概念 在解释 BFC 是什么之前,需要先介绍 Box、Formatting Context的概念。 块格式化上下文包含创建它的元素内部的所有内容. 块格式化上下文对浮动定位(参见[`float`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/float "此页面仍未被本地化, 期待您的翻译!"))与清除浮动(参见[`clear`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/clear "clear CSS 属性指定一个元素是否可以在它之前的浮动元素旁边,或者必须向下移动(清除浮动) 到这些浮动元素的下面。clear 属性适用于浮动和非浮动元素。"))都很重要。浮动定位和清除浮动时只会应用于同一个BFC内的元素。浮动不会影响其它BFC中元素的布局,而清除浮动只能清除同一BFC中在它前面的元素的浮动。外边距折叠([Margin collapsing](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing))也只会发生在属于同一BFC的块级元素之间。 ### Box: CSS布局的基本单位 Box 是 CSS 布局的对象和基本单位, 直观点来说,就是一个页面是由很多个 Box 组成的。元素的类型和 display 属性,决定了这个 Box 的类型。 不同类型的 Box, 会参与不同的 Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。让我们看看有哪些盒子: * block-level box:display 属性为 block, list-item, table 的元素,会生成 block-level box。并且参与 block fomatting context; * inline-level box:display 属性为 inline, inline-block, inline-table 的元素,会生成 inline-level box。并且参与 inline formatting context; * run-in box: css3 中才有, 这儿先不讲了。 <br> ### Formatting context Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。 CSS2.1 中只有 BFC 和 IFC, CSS3 中还增加了 GFC 和 FFC。 <br> ### BFC 定义 BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。 <br> <br> ## 布局规则 * 内部的Box会在垂直方向,一个接一个地放置。 * Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠 * 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。 * BFC的区域不会与float box重叠。 * BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。 * 计算BFC的高度时,浮动元素也参与计算 <br> <br> ## 如何创建BFC * 根元素或包含根元素的元素 * 浮动元素(元素的[`float`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/float "此页面仍未被本地化, 期待您的翻译!")不是 `none`) * 绝对定位元素(元素的 [`position`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/position "CSS position属性用于指定一个元素在文档中的定位方式。top,right,bottom 和 left 属性则决定了该元素的最终位置。")为 `absolute` 或 `fixed`) * 行内块元素(元素的 [`display`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/display "display CSS 属性指定了元素的显示类型,它包含两类基础特征,用于指定元素怎样生成盒模型——外部显示类型定义了元素怎样参与流式布局的处理,内部显示类型定义了元素内子元素的布局方式。") 为 `inline-block`) * 表格单元格(元素的 [`display`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/display "display CSS 属性指定了元素的显示类型,它包含两类基础特征,用于指定元素怎样生成盒模型——外部显示类型定义了元素怎样参与流式布局的处理,内部显示类型定义了元素内子元素的布局方式。")为 `table-cell`,HTML表格单元格默认为该值) * 表格标题(元素的 [`display`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/display "display CSS 属性指定了元素的显示类型,它包含两类基础特征,用于指定元素怎样生成盒模型——外部显示类型定义了元素怎样参与流式布局的处理,内部显示类型定义了元素内子元素的布局方式。") 为 `table-caption`,HTML表格标题默认为该值) * 匿名表格单元格元素(元素的 [`display`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/display "display CSS 属性指定了元素的显示类型,它包含两类基础特征,用于指定元素怎样生成盒模型——外部显示类型定义了元素怎样参与流式布局的处理,内部显示类型定义了元素内子元素的布局方式。")为 `table、``table-row`、 `table-row-group、``table-header-group、``table-footer-group`(分别是HTML table、row、tbody、thead、tfoot的默认属性)或 `inline-table`) * [`overflow`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/overflow "CSS属性 overflow 定义当一个元素的内容太大而无法适应 块级格式化上下文 时候该做什么。它是 overflow-x 和overflow-y的 简写属性 ")值不为 `visible`的块元素 * [`display`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/display "display CSS 属性指定了元素的显示类型,它包含两类基础特征,用于指定元素怎样生成盒模型——外部显示类型定义了元素怎样参与流式布局的处理,内部显示类型定义了元素内子元素的布局方式。")值为`[flow-root](https://drafts.csswg.org/css-display/#valdef-display-flow-root)` 的元素 * [`contain`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/contain "contain 属性允许开发者声明当前元素和它的内容尽可能的独立于 DOM 树的其他部分。这使得浏览器在重新计算布局、样式、绘图或它们的组合的时候,只会影响到有限的 DOM 区域,而不是整个页面。")值为 `layout`、`content`或 `strict` 的元素 * 弹性元素([`display`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/display "display CSS 属性指定了元素的显示类型,它包含两类基础特征,用于指定元素怎样生成盒模型——外部显示类型定义了元素怎样参与流式布局的处理,内部显示类型定义了元素内子元素的布局方式。")为 `flex` 或 `inline-flex`元素的直接子元素) * 网格元素([`display`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/display "display CSS 属性指定了元素的显示类型,它包含两类基础特征,用于指定元素怎样生成盒模型——外部显示类型定义了元素怎样参与流式布局的处理,内部显示类型定义了元素内子元素的布局方式。")为 `grid` 或 `inline-grid` 元素的直接子元素) * 多列容器(元素的 [`column-count`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/column-count "column-count CSS属性,描述元素的列数。")或 [`column-width`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/column-width "column-width CSS属性建议一个最佳列宽。 列宽是在添加另一列之前列将成为最大宽度。")不为 `auto,包括 ``column-count` 为 `1`) * `column-span` 为 `all` 的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中([标准变更](https://github.com/w3c/csswg-drafts/commit/a8634b96900279916bd6c505fda88dda71d8ec51),[Chrome bug](https://bugs.chromium.org/p/chromium/issues/detail?id=709362))。 <br> <br> ## 应用 ### 阻止元素被浮动元素覆盖 ~~~ <style> body { width: 300px; position: relative; } .aside { width: 100px; height: 150px; float: left; background: #f66; } .main { height: 200px; background: #fcc; } </style> <body> <div class="aside"></div> <div class="main"></div> </body> ~~~ 效果: ![](https://box.kancloud.cn/fea19778774a92f951a6b5de1a389100_380x245.png) 根据BFC布局规则第3条: > 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。 因此,虽然存在浮动的元素aslide,但main的左边依然会与包含块的左边相接触。 <br> <br> 据BFC布局规则第四条: > BFC的区域不会与float box重叠。 我们可以通过通过触发main生成BFC, 来实现自适应两栏布局。 ~~~ .main { overflow: hidden; } ~~~ ![](https://box.kancloud.cn/5eb1d2ba6058edaaa37ae68f9f3003ac_318x217.png) <br> <br> ### 清除浮动 ~~~ <style> .par { border: 5px solid #fcc; width: 300px; } .child { border: 5px solid #f66; width:100px; height: 100px; float: left; } </style> <body> <div class="par"> <div class="child"></div> <div class="child"></div> </div> </body> ~~~ 效果: ![](https://box.kancloud.cn/a752f18891de16bd17419c96f6103d59_336x144.png) <br> <br> 根据BFC布局规则第六条: > 计算BFC的高度时,浮动元素也参与计算 ~~~ .par { overflow: hidden; } ~~~ 效果: ![](https://box.kancloud.cn/29fa98fbd389448f3dbb83b1c530b875_328x139.png) <br> ### 解决margin折叠(传递) 子元素的margin-top传递到父级 ~~~ <style> p { color: #f55; background: #fcc; width: 200px; line-height: 100px; text-align:center; margin: 100px; } </style> <body> <p>Haha</p> <p>Hehe</p> </body> ~~~ 效果: ![](https://box.kancloud.cn/d81977b29bef0c0dd8f9184407fb34a1_404x498.png) 两个p之间的距离为100px,发生了margin重叠。 <br> <br> 根据BFC布局规则第二条: > Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠 > **使用 `writing-mode:tb-rl;` 属性会发生水平方向的重叠** 我们可以在p外面包裹一层容器,并触发该容器生成一个BFC。那么两个P便不属于同一个BFC,就不会发生margin重叠了。 ~~~ <style> .wrap { overflow: hidden; } p { color: #f55; background: #fcc; width: 200px; line-height: 100px; text-align:center; margin: 100px; } </style> <body> <p>Haha</p> <div class="wrap"> <p>Hehe</p> </div> </body> ~~~ 效果: ![](https://box.kancloud.cn/dcbcdd227a8433b5096acdec6ee5786e_418x601.png) 参考资料 [前端精选文摘:BFC 神奇背后的原理](http://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html)