面试问道BFC一定要这么讲 🍊🍉🍍

盒模型

浏览器在渲染页面时,渲染引擎会把DOM看做一个个的盒子,这些盒子的宽高以及边框由css决定,一个盒模型包括 内容区(content)、内边距(padding)、边框(border)、外边距(margin)。

盒模型又分为 标准盒模型 和 怪异盒模型,在标准盒模型中通过css设置的宽度(width)高度(height)只包含内容区,而怪异盒模型中(也叫ie盒模型)元素的宽高除了内容区外还包含内边距和边框。通过在一个DOM元素上设置 box-sizing: border-box 可以主动开启怪异盒模型模式。

标准盒模型

怪异盒模

视觉格式化模型

CSS 视觉格式化模型(visual formatting model)是用来处理和在视觉媒体上显示文档时使用的计算规则。该模型会根据盒子的边界来渲染盒子,通常盒子会创建一个包含其子元素的包含块,但是子元素并不由包含块所限制,当子元素跑到包含块的外面时称为溢出(overflow)。

盒子的生成是 CSS 视觉格式化模型的一部分,用于从文档元素生成盒子。盒子有不同的类型,盒子的类型取决于 display 属性。

  • 块盒子:display: block | list-item | table

    • 一个块级元素会被格式化成一个块,默认按照垂直方向依次排列。
    • 每个块级盒都会参与 BFC 的创建。

  • 行内盒子:display: inline | inline-block | inline-table

    • 行内元素不会生成内容块,但是可以与其他行内级内容一起显示为多行。
    • 行内级元素会生成行内级盒子,该盒子参与 IFC 的创建。

  • 匿名盒子:CSS也会创建一些无法被CSS选择器选中的盒子,我们叫它匿名盒子。

    • 匿名盒子会从父元素继承可继承属性,其他属性保持默认值initial。
    • 通常CSS引擎会自动为直接包含在块盒子中的文本创建一个匿名盒子。

<div>

Some inline text

<p>followed by a paragraph</p>

followed by more inline text.

</div>

这段代码就会产生两个匿名盒子分别是P标签前后的两端文本,Some inline textfollowed by more inline text.

渲染文档流

当确定了盒子之后,CSS引擎需要对盒子完成布局,盒子就是布局的最小单位,下面是对盒子进行布局排列的三种规则。

官方把这三种规则叫做三种定位方案,为了避免和 position 混淆,我们姑且称为规则。

普通流

在普通流的块格式化上下文中,盒子在垂直方向依次排列。

在普通流的行内格式化上下文中,盒子则水平排列。

当 CSS 的 position 属性为 static 或 relative,并且 float 为 none 时,其布局方式也为普通流。

当 position 为 relative 时为相对定位,此时该盒子还会根据 top、bottom、left 和 right 属性的值在其原本所在的位置上产生指定大小的偏移,即使有偏移,仍然保留原有的位置,其它元素不能占用这个位置。

浮动流

一个盒子的 float 值不为 none,并且其 position 为 static 或 relative 时,该盒子为浮动流。

在浮动流中,浮动盒子会浮动到当前行的开始或尾部位置。这会导致普通流中的元素会“流”到浮动盒子的边缘处(被浮动影响),除非元素通过 clear 清除了前面的浮动。

如果将 float 设置为 left,浮动盒子会流到当前行盒子的开始位置(左侧);

如果设置为 right,浮动盒子会流到当前行盒子的尾部位置(右侧);

不管是左浮动还是右浮动,行盒子都会伸缩以适应浮动盒子的大小。

定位

如果元素的 position 为 absolute(绝对定位) 或 fixed(固定定位),该元素为定位模式。

在绝对定位中,盒子会完全从当前流中脱离,对其他元素不会产生任何影响,其位置会使用 top、bottom、left 和 right 相对其最近的已定位包含块(没有则参照body)进行计算。
对固定定位的元素来说,其包含块为整个视口,该元素相对视口进行绝对定位,因此滚动时元素的位置并不会改变。

FC是啥

前面的概念都是为了给 BFC 做铺垫,现在终于可以开始聊 BFC 了。

BFC(Block Formatting Context),我们需要拆开理解,FC 表示 Formatting Context 格式化上下文,是 W3C 规范中的一个概念,它决定了页面中一块独立的渲染区域,有规定的渲染机制,决定了内部的盒子如何排列,它对外面的元素不会产生任何影响。最常见的格式化上下文有 BFC、IFC、FFC、GFC。

  • BFC(Block Formatting Context) 块级格式化上下文
  • IFC(Inline Formatting Context) 内联格式化上下文
  • FFC(Flex Formatting Context) 弹性格式化上下文
  • GFC(Grid Formatting Context) 栅格格式化上下文

BFC

BFC(Block Formatting Context) 块级格式化上下文,用于决定块级盒子的子元素布局方式以及浮动相互影响的一个独立区域,BFC只对直接子元素产生影响。 这间接说明了一个元素不能同时存在两个BFC中。

如何创建一个BFC布局:

  • 根元素(<html>
  • overflow 值不为 visible 的块元素
  • 浮动元素(元素的 float 不是 none)
  • 绝对定位元素(元素的 position 为 absolute 或 fixed)
  • display 值为 flow-root 的元素
  • 匿名表格单元格元素(元素的 display 为 table)
  • 表格单元格(元素的 display 为 table-cell,HTML表格单元格默认为该值)
  • 表格标题(元素的 display 为 table-caption,HTML表格标题默认为该值)

BFC的特性:

  • BFC内部的块级盒会在垂直方向上一个接一个排列。(普通流)
  • 计算BFC的高度时,浮动元素也会参与计算。
  • 同一BFC下的相邻块级元素可能发生外边距折叠。(float可以避免外边距折叠 或者 打破同一BFC的结构)
  • BFC元素不会和它的子元素发生外边距折叠。
  • 浮动盒的区域不会和BFC重叠。
  • BFC是一个独立的容器外面的元素不会影响BFC内部反之亦然。

BFC的应用:

📚   计算BFC的高度时,浮动元素也会参与计算。

我们在给子元素设置了float: left|right之后父元素会坍塌,经验告诉我们这个时候给父元素设置overflow: hidden可以解决这个问题让父元素撑开,之前只会用并不知道原理是啥,其实给父元素设置了overflow就开启了一个BFC,而BFC的一个特性就是浮动元素会参与高度计算也就决绝了这个问题。不管是用overflow还是position都可以解决这个问题,但是他们都会带来一些副作用,比如position会影响到已有的定位逻辑,overflow会出现滚动条或者把投影拆掉,这个时候可以用display: flow-root来开启一个BFC,相对而言是没有副作用的(注意兼容)。

子元素浮动父元素高度会坍塌,解决这个问题需要给父元素开启BFC,当根元素<html>的子元素浮动时<html>的高度并没有坍塌,这说明了根元素<html>默认就是一个BFC。再看display: flow-root属性,根据命名root表示根,就可以猜个差不多,就是创建了一个类似<html>根一样的BFC容器。

📚   同一BFC下的相邻块级元素可能发生外边距折叠

<div class="wrap">

<div class="box1"></div>

<div class="box2"></div>

</div>

.box1, .box2{

width: 100%;

height: 100px;

background: red;

/* float: left; */

}

.box1{

margin-bottom: 30px;

}

.box2{

margin-top: 30px;

}

兄弟元素的margin发生了折叠,上面 box1 和 box2 之间的距离是30px并不是60px,给 box1 和 box2 设置浮动可以解决这个问题。

还有一种做法是给box2再包一层div,并设置BFC,因为外边距折叠只发生在同一BFC下的相邻元素,破坏box1、box2在同一BFC下的结构也可以解决这个问题。

<div class="wrap">

<div class="box1"></div>

<div style="overflow: hidden;">

<div class="box2"></div>

</div>

</div>

📚   BFC元素不会和它的子元素发生外边距折叠

<div class="wrap">

<div class="box"></div>

</div>

.wrap{

margin-top: 30px;

/* display: flow-root; */

}

.box{

height: 100px;

background: pink;

margin-top: 30px;

}

父子元素的margin发生了折叠,这个例子中box距顶边的距离是30px,并不是60px。因为BFC元素不会和它的子元素发生外边距折叠,所以给wrap设置overflow: hiddendisplay: flow-root 就可以解决这个问题。

📚   浮动盒的区域不会和BFC重叠。

<div class="wrap">

<div class="box1"></div>

<div class="box2"></div>

</div>

.wrap{

border: 10px pink solid;

}

.box1{

width: 100px;

height: 100px;

background: red;

float: left;

}

.box2{

width: 200px;

height: 100px;

background: blue;

/* overflow: hidden; */

}

因为box1设置了浮动,脱离了普通文档流,导致和box2重叠,因为浮动盒的区域不会和BFC重叠,当我们给box2设置 overflow: hiddendisplay: flow-root 就可以解决这个问题。

📚   两边固定中间自适应布局

<div class="wrap">

<div class="box1">left</div>

<div class="box2">right</div>

<div class="box3">main</div>

</div>

.wrap{

border: 10px pink solid;

overflow: hidden;

}

.box1{

width: 100px;

height: 100px;

background: red;

float: left;

}

.box2{

width: 200px;

height: 100px;

background: blue;

float: right;

}

.box3{

height: 100px;

background: green;

overflow: hidden;

}

根据 “浮动盒的区域不会和BFC重叠” 特性,两边的元素浮动,中间的元素开启BFC,很容易就实现了两边固定中间自适应布局。

两边元素浮动就脱离了普通文档流,在普通文档流空出来的位置会被box3填满,这个时候box1、box2是叠在box3上面的,当给box3开启了BFC因为“浮动盒的区域不会和BFC重叠特性”box3只占中间剩余位置。

IFC

如何创建一个IFC布局:

  • 行内块元素(元素的 display 为 inline-block)

IFC的特性

  • 在行内格式化上下文中,盒(box)一个接一个地水平排列,起点是包含块的顶部
  • 水平方向上的 margin,border 和 padding在盒之间得到保留
  • 盒在垂直方向上可以以不同的方式对齐

FFC

如何创建一个FFC布局:

  • 弹性元素(display 为 flex 或 inline-flex)

GFC

如何创建一个GFC布局:

  • 网格元素(display 为 grid 或 inline-grid)


记得点赞~

以上是 面试问道BFC一定要这么讲 &#x1f34a;&#x1f349;&#x1f34d; 的全部内容, 来源链接: utcz.com/a/36080.html

回到顶部