资讯专栏INFORMATION COLUMN

理解 BFC (Block Formatting Model)

Tonny / 903人阅读

摘要:是指块级元素,就是会强制换行的元素,比如。将元素推向左侧。请根据不同的实际情况,选择最合适的方式。再次重申一下,是为子元素创建定位环境。,由于浮动元素占据了一定的宽度,新创建的会因此而变窄。这里只是为了更好地去理解而做一个例子。

什么是 BFC

W3C 为浏览器规定了三种定位模型:Normal Flow, 浮动, 和绝对定位。本文所介绍的 BFC (Block Formatting Model) 是属于 Normal Flow 中的一小节内容,并且这部分内容只有三段话。第一段:

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.

简单来说,BFC 仅仅是一种定位的情况,即当元素满足 BFC 的条件时,浏览器怎么去显示它。上面这短话讲的是如何建立 BFC,只要满足其中任何一个条件就可以了。可能需要解释一句话,就是:block containers that are not block boxes。

block box 是指块级元素,就是会强制换行的元素,比如 div。block container 是指可以包含块级元素的元素,但它不一定要换行,比如 div, td。可以看到,后者的范围更大一点,两者异或的结果就是这句话的意思了。除了规范上列举的 inline-block、table-cell 等,主流浏览器还支持 flex 。

建立 BFC

默认的 div 是块级元素,并不是 BFC,所以需要一些额外的样式来生成。按照规范,我们大概有如下(不止)的手段,以及相应的代价:

disblay: table; 无法解决响应式的问题。

display: inline-block; 会使后续内联元素显示在同一行。

position: absolute; 将元素从 normal flow 中剥离出来。

float: left; 将元素推向左侧。

overflow: scroll; 会出现滚动条。

overflow: hidden; 会截断溢出的内容。

请根据不同的实际情况,选择最合适的方式。

仔细想一下,在 normal flow 的章节中写道,用 float: left; 或者 position: absolute; 去创建 BFC,是不是有点矛盾?不然。BFC 指的是为子元素创建一个定位环境,浮动和绝对定位是针对该元素本身,而不是其子元素。

外边距合并

在 normal flow 中,我们知道,垂直方向上相邻元素的外边距取两者中较大的值,例子:

第一块
第二块
第三块

相应的 CSS:

.container {margin:20px;border:1px solid #212121;width:300px;background-color:#009688;}
.c1 {margin:10px 0;height:40px;background-color:#FFC107;}

结果示意图:

可以看到,每个黄色块之间的距离是 10px,而不是相加的 20px 。扩展一下,如果用 .c1 {margin:10px 0 15px;} 那么黄色块之间的距离就是 15px,取较大值。如果是 .c1 {margin:10px 0 -15px;} 呢?是 10px,还是 0px,还是 -5px?

关于边距合并,规范中是这么描述的:

Vertical margins between adjacent block-level boxes in a block formatting context collapse.

也就是说,边距合并的条件是,子元素处于相同的 BFC 中,如果为其中一个子元素创建新的 BFC,就不会发生合并的情况了。

第三块

现在为第三块添加一个额外的父元素,并且为该元素创建 BFC:

.extra {overflow:hidden;}

图不多带带给了,这里给个问题,就是,如果不添加父元素,直接把 .extra 类加给第三个块,如下:

第一块
第二块
第三块

可以防止边距合并吗?不行。再次重申一下,BFC 是为元素创建定位环境。

BFC 的应用 清除浮动

如果一个块级元素的所有子元素都浮动了,那么它的高度就为 0 。

.c1 {float:left;margin:10px;width:100px;height:50px;background-color:#FFC107;}

对于同样的 html,修改 .c1的样式,添加浮动的效果,可以看到

父元素只剩下了边框,并没有 content height 。如果要清除浮动,可以为容器添加伪类:

.container:after{display:block;content:"";clear:both;}

这样,父元素的高度就又回来了。

当然,我们也可以为父元素添加 overflow:hidden; 来清除浮动。

.container {overflow:hidden;}

这两个方法都可行,前者很直白,clear:both; 本来就是用于清除浮动的,为什么用 overflow:hidden 也可以?因为这样就创建了一个 BFC,对于子元素的排列,规范是这么写的:

In a block formatting context, each box"s left outer edge touches the left edge of the containing block. This is true even in the presence of floats, unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).

子元素的外边缘会触碰到父元素的左侧(严格来说是,子元素外边距和父元素的内边距)。如果父元素的高度为 0,那么就违背规范了。

所以为父元素添加浮动、绝对定位等任何用于创建 BFC 的方式,都可以清除浮动。

防止文字环绕

常见的一种布局就是,特别是评论回复中,会看到在头像右侧有一段文字,就算文字很长,也不会出现在头像下方,会一直保持在右侧。

这样的 HTML 格式很简单:

...

.comment 中的内容省略不写了。如果仅仅对 .avatar 左浮,就会出现文字环绕现象:

解决的办法可以是为 .comment 添加一个适当的左外边距,比如 90px 。

另一个办法是利用 BFC 。

根据规范,子元素的外边距必须向左靠着父元素的内边距,也就是说,尽管 .avatar 浮动了,但是 .comment 还是会靠着父元素的左侧内边距,它们两者是上下重叠的!

unless the box establishes a new block formatting context,这句话表明,只要为 .comment 创建 BFC,那么这个约束就可以被打破,即它们不会重叠。

in which case the box itself may become narrower due to the floats,由于浮动元素占据了一定的宽度,新创建的 BFC 会因此而变窄。

.avatar {width:70px;height:70px;float:left;margin:10px;background-color:#ffc107;}
.comment {overflow:hidden;}
多列布局

一般来说,如果要做宽度自适应的多列布局,就会用百分比做宽度单位,并且子元素浮动。那么问题就是,如果百分比换算到像素时,一旦子元素的宽度之和大于父元素,最后一列就会换行。

CSS3 本身可以实现多列布局,用 columns 属性或者 flex 布局。这里只是为了更好地去理解 BFC 而做一个例子。

.column {float:left;margin:0 1%;width:31.33%;height:100px;background-color:#ffc107;}

先来算一下,左右边距各 1%,宽度 31.33%,三列布局,总共 99.99%,应该不会超。但对于部分浏览器,宽度换算时是四舍五入的,比如,父元素的宽度为 500px,那么四舍五入,每列宽度为 157px,左右边距 5px,总和 (157 + 5 2) 3 = 501,正好超 1px,最后一列换行。

最后一列要换行是因为浮动元素的特性,如果它不是浮动元素,那么就可以按照 normal flow 的规则来,即,向左靠至父元素左边距。

然后,根据上个小节的知识,如果为元素创建新的 BFC,那么“向左靠”的规则可以打破。两个条件结合,得到:

.column:last-child {float:none;overflow:hidden;}

虽然可以防止换行,但是最后一列的间距有点不一致。

本文主要是讲了 BFC 的两个关键点,第一:如何创建,以及每种方式的代价;第二:特性,防止默认的边距合并和向左靠至父元素内侧。很多衍生用法都是基于这两种特性来的。

不过,往往我们是直接去记用 overflow:hidden; 可以清除浮动,并没有想为什么,毕竟内容不多。有时候想想原理,也挺有意思的。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/111151.html

相关文章

  • 前端进阶之什么是BFCBFC的原理是什么?如何创建BFC

    摘要:官方说法就是它规定了用户端在媒介中如何处理文档树。是的包含块,同时又是的包含块,不是绝对的。因此称为匿名盒子。行内盒子行内级元素会生成行内级盒子,该盒子同时会参与行内格式化上下文的创建。如果只有一个值指定为,则其使用的值来自相等。 作者:陈大鱼头 github: KRISACHAN 盒模型 The CSS box model describes the rectangular b...

    lowett 评论0 收藏0
  • CSS魔法堂:hasLayout原来是这样的!

    摘要:到底是何方神圣可以简单看作是中的。和产生新的特性一样,无法通过属性直接设置,而是通过某些属性间接开启这一特性。不同的是某些属性是以不可逆方式间接开启为。因此所引发的问题,很大程度可以理解为在不应该的或没有预料到的地方产生新的导致的。 前言 过去一直听说旧版本IE下很多诡异bug均由一个神秘角色引起的,那就是hasLayout。趁着最近突然发神经打算好好学习CSS,顺便解答多年来的疑惑。...

    URLOS 评论0 收藏0
  • 想要清晰的明白(一): CSS视觉格式化模型|盒模型|定位方案|BFC

    摘要:并且这种过程遵循标准的描述只要不是和绝对定位方式布局的,都在普通流里面。定位相对定位在普通流之中,是相对于它在普通流中的位置中进行移动,元素占据原来位置绝对定位脱离普通流,不占据空间相对于距离它最近的那个已定位的祖先相对绝对元素决定的。 视觉格式化模型 页面(文档树)可以想象成是由一个个的Box组合而成的,而视觉格式化模型(Visual formatting model)是一套规则,将...

    Edison 评论0 收藏0
  • CSS中的语法与概念

    摘要:属性语法层面仅对属性作粗略分类。重点还是概念均决定了布局基础模式。常规布局的重心与难点。对应标准第章布局上下文格式化上下文在常规流中的框,都属于一个格式化的上下文中规则脱胎自文字排印,核心概念是。 发端自此。本文细节从略,只做主干梳理。 showImg(https://segmentfault.com/img/bVpFuh); 这个树主要还是在借CSS2.1标准的骨架,填充进一些新的C...

    funnyZhang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<