CSS

前言

FC的全称是:Formatting Contexts,译作格式化上下文,是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。
「CSS2.1中只有BFC和IFC,CSS3中才有GFC和FFC。」

前置概念

在学习各种「FC」之前,先来了解几个基本概念:

Box(CSS布局基本单位)

简单来讲,看到的所有页面都是由一个个Box组合而成的,元素的类型和display属性决定了Box的类型。

  • 「block-level Box:」 当元素的 CSS 属性 display 为 block, list-item 或table 时,它是「块级元素」 block-level。块级元素(比如

    )视觉上呈现为块,竖直排列。每个块级元素至少生成一个块级盒(block-level Box)参与 BFC ,称为主要块级盒(principal block-level box)。一些元素,比如

  • ,生成额外的盒来放置项目符号,不过多数元素只生成一个主要块级盒。
  • 「Inline-level Box:」 当元素的 CSS 属性 display 的计算值为inline,inline-block 或inline-table 时,称它为「行内级元素」。视觉上它将内容与其它行内级元素排列为多行。典型的如段落内容,有文本或图片,都是行内级元素。行内级元素生成行内级盒(inline-level boxes),参与行内格式化上下文 IFC 。
  • 「flex container:」 当元素的 CSS 属性 display 的计算值为 flex 或 inline-flex ,称它为「弹性容器」。display:flex这个值会导致一个元素生成一个块级(block-level)弹性容器框。display:inline-flex这个值会导致一个元素生成一个行内级(inline-level)弹性容器框。
  • 「grid container:「当元素的 CSS 属性 display 的计算值为 grid 或inline-grid,称它为」栅格容器」

    块容器盒(block container box)

    只包含其它块级盒,或生成一个行内格式化上下文(inline formatting context),只包含行内盒的叫做「块容器盒子」
    也就是说,块容器盒要么只包含行内级盒,要么只包含块级盒。
    块级盒(block-level Box)是描述元素跟它的父元素与兄弟元素之间的表现。
    块容器盒(block container box)描述元素跟它的后代之间的影响。

    块盒(BLock Boxes)

    同时是块容器盒的块级盒称为块盒(block boxes)

    行盒(Line boxes)

    行盒由行内格式化上下文(inline formatting context)产生的盒,用于表示一行。在块盒里面,行盒从块盒一边排版到另一边。当有浮动时, 行盒从左浮动的最右边排版到右浮动的最左边。
    了解完上面这些概念,再来看本篇的重点内容。

    BFC(Block Formatting Contexts)块级格式化上下文

    什么是BFC?

    BFC 全称:Block Formatting Context, 名为 「块级格式化上下文」
    W3C官方解释为:BFC它决定了元素如何对其内容进行定位,以及与其它元素的关系和相互作用,当涉及到可视化布局时,Block Formatting Context提供了一个环境,HTML在这个环境中按照一定的规则进行布局。

    如何触发BFC?

  • 根元素或其它包含它的元素

  • 浮动 float: left/right/inherit
  • 绝对定位元素 position: absolute/fixed
  • 行内块display: inline-block
  • 表格单元格 display: table-cell
  • 表格标题 display: table-caption
  • 溢出元素 overflow: hidden/scroll/auto/inherit
  • 弹性盒子 display: flex/inline-flex

    BFC布局规则

  • 内部的Box会在垂直方向,一个接一个地放置。

  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。
  • 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  • BFC的区域不会与float box重叠。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算

    BFC应用场景

    解决块级元素垂直方向margin重叠

    来看下面这种情况:

    1. <style>
    2. .box{
    3. width:180px;
    4. height:180px;
    5. background:rosybrown;
    6. color:#fff;
    7. margin: 60px auto;
    8. }
    9. </style>
    10. <body>
    11. <div class="box">nanjiu</div>
    12. <div class="box">南玖</div>
    13. </body>

    按习惯性思维,上面这个box的margin-bottom是60px,下面这个box的margin-top也是60px,那他们垂直的间距按道理来说应该是120px才对。(可事实并非如此,可以来具体看一下)
    BFC、IFC、GFC 和 FFC - 图1
    「从图中可以看到,两个box的垂直间距只有60px,并不是120px!」
    这种情况下的margin边距为两者的最大值,而不是两者相加,那么可以使用BFC来解决这种margin塌陷的问题。

    1. <style>
    2. .box{
    3. width:180px;
    4. height:180px;
    5. background:rosybrown;
    6. color:#fff;
    7. margin: 60px auto;
    8. }
    9. .outer_box{
    10. overflow: hidden;
    11. }
    12. </style>
    13. <body>
    14. <div class="outer_box">
    15. <div class="box">nanjiu</div>
    16. </div>
    17. <div class="box">南玖</div>
    18. </body>

    BFC、IFC、GFC 和 FFC - 图2
    由上面可以看到,通过给第一个box外面再包裹一层容器,并触发它形成BFC,此时的两个box就不属于同一个BFC了,它们的布局互不干扰,所以这时候他们的垂直间距就是两者间距相加了。

    解决高度塌陷问题

    再来看这种情况,内部box使用float脱离了普通文档流,导致外层容器没办法撑起高度,使得背景颜色没有显示出来。

    1. <style>
    2. .box{
    3. float:left;
    4. width:180px;
    5. height:180px;
    6. background:rosybrown;
    7. color:#fff;
    8. margin: 60px;
    9. }
    10. .outer_box{
    11. background:lightblue;
    12. }
    13. </style>
    14. <body>
    15. <div class="outer_box">
    16. <div class="box">nanjiu</div>
    17. <div class="box">南玖</div>
    18. </div>
    19. </body>

    BFC、IFC、GFC 和 FFC - 图3
    从这张图,可以看到此时的外层容器的高度为0,导致背景颜色没有渲染出来,这种情况同样可以使用BFC来解决,可以直接为外层容器触发BFC,来看看效果:

    1. <style>
    2. .box{
    3. float:left;
    4. width:180px;
    5. height:180px;
    6. background:rosybrown;
    7. color:#fff;
    8. margin: 60px;
    9. }
    10. .outer_box{
    11. display:inline-block;
    12. background:lightblue;
    13. }
    14. </style>
    15. <body>
    16. <div class="outer_box">
    17. <div class="box">nanjiu</div>
    18. <div class="box">南玖</div>
    19. </div>
    20. </body>

    BFC、IFC、GFC 和 FFC - 图4

    清除浮动

    在早期前端页面大多喜欢用浮动来布局,但浮动元素脱离普通文档流,会覆盖旁边内容:

    1. <style>
    2. .aside {
    3. float: left;
    4. width:180px;
    5. height: 300px;
    6. background:lightpink;
    7. }
    8. .container{
    9. width:500px;
    10. height:400px;
    11. background:mediumturquoise;
    12. }
    13. </style>
    14. <body>
    15. <div class="outer_box">
    16. <div class="aside">nanjiu</div>
    17. <div class="container">南玖</div>
    18. </div>
    19. </body>

    BFC、IFC、GFC 和 FFC - 图5
    可以通过触发后面这个元素形成BFC,从而来清楚浮动元素对其布局造成的影响

    1. <style>
    2. .aside {
    3. float: left;
    4. width:180px;
    5. height: 300px;
    6. background:lightpink;
    7. }
    8. .container{
    9. width:500px;
    10. height:400px;
    11. background:mediumturquoise;
    12. overflow: hidden;
    13. }
    14. </style>
    15. <body>
    16. <div class="outer_box">
    17. <div class="aside">nanjiu</div>
    18. <div class="container">南玖</div>
    19. </div>
    20. </body>

    BFC、IFC、GFC 和 FFC - 图6

    IFC(Inline Formatting Contexts)行内级格式化上下文

    什么是IFC?

    IFC全称:Inline Formatting Context,名为「行级格式化上下文」

    如何触发IFC?

  • 块级元素中仅包含内联级别元素

形成条件非常简单,需要注意的是当IFC中有块级元素插入时,会产生两个匿名块将父元素分割开来,产生两个IFC。

IFC布局规则

  • 在一个IFC内,子元素是水平方向横向排列的,并且垂直方向起点为元素顶部。
  • 子元素只会计算横向样式空间,【padding、border、margin】,垂直方向样式空间不会被计算,【padding、border、margin】。
  • 在垂直方向上,子元素会以不同形式来对齐(vertical-align)
  • 能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框(line box)。行框的宽度是由包含块(containing box)和与其中的浮动来决定。
  • IFC中的line box一般左右边贴紧其包含块,但float元素会优先排列。
  • IFC中的line box高度由 CSS 行高计算规则来确定,同个IFC下的多个line box高度可能会不同。
  • 当 inline boxes的总宽度少于包含它们的line box时,其水平渲染规则由 text-align 属性值来决定。
  • 当一个inline box超过父元素的宽度时,它会被分割成多个boxes,这些boxes分布在多个line box中。如果子元素未设置强制换行的情况下,inline box将不可被分割,将会溢出父元素。

    IFC应用场景

    元素水平居中

    当一个块要在环境中水平居中时,设置其为inline-block则会在外层产生IFC,通过text-align则可以使其水平居中。
    1. <style>
    2. /* IFC */
    3. .text_container{
    4. width: 650px;
    5. border: 3px solid salmon;
    6. margin-top:60px;
    7. text-align: center;
    8. }
    9. strong,span{
    10. /* border:1px solid cornflowerblue; */
    11. margin: 20px;
    12. background-color: cornflowerblue;
    13. color:#fff;
    14. }
    15. </style>
    16. <body>
    17. <div class="text_container">
    18. <strong>众里寻他千百度,南玖需要你关注</strong>
    19. <span>蓦然回首,那人却在,南玖前端交流群</span>
    20. </div>
    21. </body>
    BFC、IFC、GFC 和 FFC - 图7

    多行文本水平垂直居中

    创建一个IFC,然后设置其vertical-align:middle,其他行内元素则可以在此父元素下垂直居中。 ```html

    东风夜放花千树,更吹落,星如雨。宝马雕车香满路。凤箫声动,玉壶光转,一夜鱼龙舞。蛾儿雪柳黄金缕,笑语盈盈暗香去。 众里寻他千百度,蓦然回首,那人却在,灯火阑珊处。

  1. ![](https://cdn.nlark.com/yuque/0/2022/webp/396745/1645402433294-2a01fbf2-e0ec-41cb-b662-04758577ba77.webp#clientId=ub82b7825-f730-4&from=paste&id=ue8301d68&originHeight=242&originWidth=1080&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u8659996c-e64c-4624-a4f9-df95cb657fc&title=)
  2. <a name="wGPwY"></a>
  3. ## GFC(Grid Formatting Contexts)栅格格式化上下文
  4. <a name="UX1DI"></a>
  5. ### 什么是GFC?
  6. GFC全称:Grids Formatting Contexts,名为**「网格格式上下文」**<br />简介:CSS3引入的一种新的布局模型——Grids网格布局,目前暂未推广使用,使用频率较低,简单了解即可。Grid 布局与 Flex 布局有一定的相似性,都可以指定容器内部多个项目的位置。但是,它们也存在重大区别。Flex 布局是轴线布局,只能指定"项目"针对轴线的位置,可以看作是一维布局。Grid 布局则是将容器划分成"行""列",产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局。Grid 布局远比 Flex 布局强大。
  7. <a name="njsW2"></a>
  8. ### 如何触发GFC?
  9. 当为一个元素设置display值为grid或者inline-grid的时候,此元素将会获得一个独立的渲染区域。
  10. <a name="nGPQZ"></a>
  11. ### GFC布局规则
  12. 通过在网格容器(grid container)上定义网格定义行(grid definition rows)和网格定义列(grid definition columns)属性各在网格项目(grid item)上定义网格行(grid row)和网格列(grid columns)为每一个网格项目(grid item)定义位置和空间(具体可以在MDN上查看)
  13. <a name="z5eTV"></a>
  14. ### GFC应用场景
  15. <a name="FSdVE"></a>
  16. #### 任意魔方布局
  17. 这个布局使用用GFC可以轻松实现自由拼接效果,换成其他方法,一般会使用相对/绝对定位,或者flex来实现自由拼接效果,复杂程度将会提升好几个等级。
  18. ```html
  19. <style>
  20. .magic{
  21. display: grid;
  22. grid-gap: 2px;
  23. width:300px;
  24. height:300px;
  25. }
  26. .magic div{
  27. border: 1px solid coral;
  28. }
  29. .m_1{
  30. grid-column-start: 1;
  31. grid-column-end: 3;
  32. }
  33. .m_3{
  34. grid-column-start: 2;
  35. grid-column-end: 4;
  36. grid-row-start: 2;
  37. grid-row-end: 3;
  38. }
  39. </style>
  40. <body>
  41. <div class="magic">
  42. <div class="m_1">1</div>
  43. <div class="m_2">2</div>
  44. <div class="m_3">3</div>
  45. <div class="m_4">4</div>
  46. <div class="m_5">5</div>
  47. <div class="m_6">6</div>
  48. <div class="m_7">7</div>
  49. </div>
  50. </body>

BFC、IFC、GFC 和 FFC - 图8

FFC(Flex Formatting Contexts)弹性格式化上下文

什么是FFC?

FFC全称:Flex Formatting Contexts,名为「弹性格式上下文」
简介:「CSS3引入了一种新的布局模型——flex布局。」flex是flexible box的缩写,一般称之为「弹性盒模型」。和CSS3其他属性不一样,flexbox并不是一个属性,而是一个模块,包括多个CSS3属性。flex布局提供一种更加有效的方式来进行容器内的项目布局,以适应各种类型的显示设备和各种尺寸的屏幕,使用Flex box布局实际上就是声明创建了FFC(自适应格式上下文)

如何触发FFC?

当 display 的值为 flex 或 inline-flex 时,将生成弹性容器(Flex Containers), 一个弹性容器为其内容建立了一个新的弹性格式化上下文环境(FFC)

FFC布局规则

  • 设置为 flex 的容器被渲染为一个块级元素
  • 设置为 inline-flex 的容器被渲染为一个行内元素
  • 弹性容器中的每一个子元素都是一个弹性项目。弹性项目可以是任意数量的。弹性容器外和弹性项目内的一切元素都不受影响。简单地说,Flexbox 定义了弹性容器内弹性项目该如何布局

「⚠️注意:」 FFC布局中,float、clear、vertical-align属性不会生效。
Flex 布局是轴线布局,只能指定”项目”针对轴线的位置,可以看作是「一维布局」。Grid 布局则是将容器划分成”行”和”列”,产生单元格,然后指定”项目所在”的单元格,可以看作是「二维布局」。Grid 布局远比 Flex 布局强大。

FFC应用场景

这里只介绍它对于其它布局所相对来说更方便的特点,其实flex布局现在是非常普遍的,很多前端人员都喜欢用flex来写页面布局,操作方便且灵活,兼容性好。

自动撑开剩余高度/宽度

看一个经典两栏布局:左边为侧边导航栏,右边为内容区域,用之前的常规布局,可能就需要使用到css的calc方法来动态计算剩余填充宽度了,但如果使用flex布局的话,只需要一个属性就能解决这个问题:
「calc动态计算方法:」

  1. <style>
  2. .outer_box {
  3. width:100%;
  4. }
  5. .aside {
  6. float: left;
  7. width:180px;
  8. height: 300px;
  9. background:lightpink;
  10. }
  11. .container{
  12. width:calc(100% - 180px);
  13. height:400px;
  14. background:mediumturquoise;
  15. overflow: hidden;
  16. }
  17. </style>
  18. <body>
  19. <div class="outer_box">
  20. <div class="aside">nanjiu</div>
  21. <div class="container">南玖</div>
  22. </div>
  23. </body>

BFC、IFC、GFC 和 FFC - 图9
「使用FFC:」

  1. <style>
  2. .outer_box {
  3. display:flex;
  4. width:100%;
  5. }
  6. .aside {
  7. float: left;
  8. width:180px;
  9. height: 300px;
  10. background:lightpink;
  11. }
  12. .container{
  13. flex: 1;
  14. height:400px;
  15. background:mediumturquoise;
  16. overflow: hidden;
  17. }
  18. </style>
  19. <body>
  20. <div class="outer_box">
  21. <div class="aside">nanjiu</div>
  22. <div class="container">南玖</div>
  23. </div>
  24. </body>

BFC、IFC、GFC 和 FFC - 图10

总结

一般来说,「FFC能做的事情,通过GFC都能搞定,反过来GFC能做的事通过FFC也能实现。」通常弹性布局使用FFC,二维网格布局使用GFC,所有的FFC与GFC也是一个BFC,在遵循自己的规范的情况下,向下兼容BFC规范。