理解BFC、IFC

常见定位方案

普通流 (normal flow)

在普通流中,元素按照其在 HTML 中的前后位置至上而下布局,在这个过程当中,行内元素水平排列,直到当行被占满而后换行,块级元素则会被渲染为完整的一个新行,除非另外指定,不然全部元素默认都是普通流定位,也能够说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。css

浮动 (float)

在浮动布局中,元素首先按照普通流的位置出现,而后根据浮动的方向尽量的向左边或右边偏移,其效果与印刷排版中的文本环绕类似html

绝对定位 (absolute positioning)

在绝对定位布局中(position值为absolute或fixed),元素会总体脱离普通流,所以绝对定位元素不会对其兄弟元素形成影响,而元素具体的位置由绝对定位的坐标决定。git

Formatting context(格式化上下文)

Formatting context(格式化上下文) 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,而且有一套渲染规则,它决定了其子元素将如何定位,以及和其余元素的关系和相互做用github

格式化上下文有如下几种类型:segmentfault

  • BFC: 块级格式化上下文
  • IFC: 行内格式化上下文
  • 其余格式化上下文(GFC/FFC)

Box

一个页面是由不少个Box组成的,元素的类型和display属性决定了这个Box的类型。不一样类型的 Box,会参与不一样的 Formatting Context。
Block level的box会参与造成BFC,好比display值为block,list-item,table的元素。
Inline level的box会参与造成IFC,好比display值为inline,inline-table,inline-block的元素。ide

BFC

块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视化CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其余元素交互的区域。(我的理解:BFC布局方式和上述普通流布局方式类似)布局

具备 BFC 特性的元素能够看做是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,而且 BFC 具备普通容器所没有的一些特性。flex

下列方式会建立块级格式化上下文:ui

  • 根元素(<html>)
  • 浮动元素(元素的float不是 none
  • 绝对定位元素(元素的 position为 absolute 或 fixed
  • 行内块元素(元素的 display 为 inline-block
  • 表格单元格(元素的 display为 table-cell,HTML表格单元格默认为该值)
  • 表格标题(元素的 display 为 table-caption,HTML表格标题默认为该值)
  • 匿名表格单元格元素(元素的 display为 table、`table-row、 table-row-group、table-header-group、table-footer-group(分别是HTML table、row、tbody、thead、tfoot的默认属性)或 inline-table`)
  • overflow值不为 visible的块元素
  • display值为 flow-root 的元素
  • contain值为 layoutcontent或paint 的元素
  • 弹性元素(display为 flex 或 inline-flex元素的直接子元素)
  • 网格元素(display为 grid 或 inline-grid 元素的直接子元素)
  • 多列容器(元素的 column-count或 column-width不为 auto,包括 `column-count 为 1`)
  • column-span 为 all 的元素始终会建立一个新的BFC,即便该元素没有包裹在一个多列容器中(标准变动Chrome bug)。

块格式化上下文包含建立它的元素内部的全部内容.spa

BFC布局规则

  • 内部的Box会在垂直方向,一个接一个地放置。
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
  • 每一个元素的左外边缘(margin-left), 与包含块的左边(contain box left)相接触(对于从左往右的格式化,不然相反)。即便存在浮动也是如此。除非这个元素本身造成了一个新的BFC。
  • BFC的区域不会与float box重叠。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算

BFC的特性和应用

BFC 能够包含浮动的元素(清除浮动带来的影响)

浮动的元素会脱离普通文档流

<div style="border: 1px solid #000;">
    <div style="width: 100px;height: 100px;background: #eee;float: left;"></div>
</div>

1.jpg

因为容器内元素浮动,脱离了文档流,因此容器只剩下 2px 的边距高度。若是使触发容器的 BFC,那么容器将会包裹着浮动元素。

效果如图:
2.png

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

先来看一个文字环绕效果:

<div style="height: 100px;width: 100px;float: left;background: lightblue">我是一个左浮动的元素</div>
<div style="width: 200px; height: 200px;background: #eee">我是一个没有设置浮动, 
也没有触发 BFC 元素, width: 200px; height:200px; background: #eee;</div>

3.png

这时候其实第二个元素有部分被浮动元素所覆盖,(可是文本信息不会被浮动元素所覆盖) 若是想避免元素被覆盖,可触第二个元素的 BFC 特性,在第二个元素中加入overflow: hidden,就会变成:
4.png

这个方法能够用来实现两列自适应布局,效果不错,这时候左边的宽度固定,右边的内容自适应宽度(去掉上面右边内容的宽度)。

解决外边距合并

相邻兄弟元素margin折叠问题

<head>
div{
    width: 100px;
    height: 100px;
    background: lightblue;
    margin: 100px;
}
</head>
<body>
    <div></div>
    <div></div>
</body>

5.png
从效果上看,由于两个 div 元素都处于同一个 BFC 容器下 (这里指 body 元素) 因此第一个 div 的下边距和第二个 div 的上边距发生了重叠,因此两个盒子之间距离只有 100px,而不是 200px。

首先这不是 CSS 的 bug,咱们能够理解为一种规范,若是想要避免外边距的重叠,能够将其放在不一样的 BFC 容器中。

<div class="container">
    <p></p>
</div>
<div class="container">
    <p></p>
</div>
.container {
    overflow: hidden;
}
p {
    width: 100px;
    height: 100px;
    background: lightblue;
    margin: 100px;
}

这时候,两个盒子边距就变成了 200px
6.png

父子元素margin重叠问题

<style>
.box{
width:100px;
height:100px;
background:#ccc;
}
.wrap {
  background:yellow;
}
.wrap h1{
  background:pink;
  margin:40px;
}
</style>
<body>
<div class="box">box</div>
<div class="wrap">
  <h1>h1</h1>
</div>
</body>

7.png

上图wrap元素与h1元素之间l理论上本该有个40px的上下margin值,然而实际上父子元素并无存在margin值,与此同时,两个div元素的间距为40px。遇到这种情形,咱们如何处理?
处理方法其实有不少,在wrap元素中添加:overflow:hidden;或者overflow:auto;使其父元素造成一个BFC;也能够在wrap元素中添加border:1px solid;或是padding:1px;这些均可以有效解决父子元素margin重叠问题。

8.png

IFC

IFC(Inline Formatting Contexts)直译为"内联格式化上下文",IFC的line box(线框)高度由其包含行内元素中最高的实际高度计算而来(不受到竖直方向的padding/margin影响)。

IFC中框模型不彻底适用于参与内联格式上下文的项。在水平书写模式行中,水平填充、边框和边距将应用于元素,并左右推送文本。可是,不会应用元素上下的边距。将应用垂直填充和边框,但可能会在内容的上方和下方重叠,由于在内联格式上下文中,填充和边框不会将行框推开

IFC布局规则

在行内格式化上下文中,框(boxes)一个接一个地水平排列,起点是包含块的顶部。水平方向上的marginborderpadding在框之间获得保留。框在垂直方向上能够以不一样的方式对齐:它们的顶部或底部对齐,或根据其中文字的基线对齐。包含那些框的长方形区域,会造成一行,叫作行框。

IFC 的应用

水平居中

当一个块要在环境中水平居中时,设置其为inline-block则会在外层产生IFC,经过text-align则可使其水平居中。

垂直居中

建立一个IFC,用其中一个元素撑开父元素的高度,而后设置其vertical-align:middle,其余行内元素则能够在此父元素下垂直居中。

其余格式化上下文

GFC

GFC(GridLayout Formatting Contexts)直译为"网格布局格式化上下文",当为一个元素设置display值为grid的时候,此元素将会得到一个独立的渲染区域,咱们能够经过在网格容器(grid container)上定义网格定义行(grid definition rows)和网格定义列(grid definition columns)属性各在网格项目(grid item)上定义网格行(grid row)和网格列(grid columns)为每个网格项目(grid item)定义位置和空间。 

GFC将改变传统的布局模式,他将让布局从一维布局变成了二维布局。简单的说,有了GFC以后,布局再也不局限于单个维度了。这个时候你要实现相似九宫格,拼图之类的布局效果显得格外的容易。

FFC

FFC(Flex Formatting Contexts)直译为"自适应格式化上下文",display值为flex或者inline-flex的元素将会生成自适应容器(flex container)。

Flex Box 由伸缩容器和伸缩项目组成。经过设置元素的 display 属性为 flex 或 inline-flex 能够获得一个伸缩容器。设置为 flex 的容器被渲染为一个块级元素,而设置为 inline-flex 的容器则渲染为一个行内元素。

伸缩容器中的每个子元素都是一个伸缩项目。伸缩项目能够是任意数量的。伸缩容器外和伸缩项目内的一切元素都不受影响。简单地说,Flexbox 定义了伸缩容器内伸缩项目该如何布局。

总体来讲,FFC与BFC有点儿相似,但仍有如下几点区别:

  • Flexbox 不支持 ::first-line 和 ::first-letter 这两种伪元素
  • vertical-align 对 Flexbox 中的子元素 是没有效果的
  • float 和 clear 属性对 Flexbox 中的子元素是没有效果的,也不会使子元素脱离文档流(可是对Flexbox 是有效果的!)
  • 多栏布局(column-*) 在 Flexbox 中也是失效的,就是说咱们不能使用多栏布局在Flexbox 排列其下的子元素
  • Flexbox 下的子元素不会继承父级容器的宽

参考

https://developer.mozilla.org...
https://developer.mozilla.org...
https://segmentfault.com/a/11...
https://zhuanlan.zhihu.com/p/...

相关文章
相关标签/搜索