从清除浮动引起的BFC,IFC,FFC再学习

2020-05-13  本文已影响0人  DLLCNX

水平有限,如果存在问题欢迎大家访问我的博客批评指正.

正文

首先,'FC'肯定不是开封菜,而是Formatting context的简称.而在理解BFC等等概念之前,先让我们了解一下'FC'与'Box'是什么?

-Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)以及Flex formatting contexts(简称FFC),最后还有一个GridLayout Formatting Contexts(GFC)。

Box是 CSS 布局的对象和基本单位, 直观点来说,就是一个页面是由很多个 Box 组成的。元素的类型和 display 属性,决定了这个 Box 的类型。 不同类型的 Box, 会参与不同的 Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。让我们看看有哪些盒子:

在我们一些使用场景触发BFC是为了清除浮动(我此次是因为清除浮动才引起的整体学习),所以我还得先讲讲清除浮动.

清除浮动

为什么要清除浮动?

清除浮动主要是为了解决,父元素因为子级元素浮动引起的内部高度为0的问题

1.如下,我给父div设置一个边框,内部放两个div一个left 一个right,不设置浮动,则他们会默认撑开父盒子

<body>
    <div class="father">
        <div class="left">left</div>
        <div class="right">right</div>
    </div>
    <div class="footer">footer</div>
</body>

  <style>
    .father{
        width: 60vw;
        border: 5px solid #000;
    }
    .left{
        width: 30vw;
        height: 200px;
        background: green;
    }
    .right{
        width: 25vw;
        height: 100px;
        background: blue;
    }
    .footer{
        width: 60vw;
        height: 60px;
        background: red;
        border:3px solid rgb(194, 246, 6);
    }
    </style>
title

2.当我给内部两个div加上float属性的时候

title

两个div左右浮动了,而父div因为没高度,只剩下黑色边框了.红色的footer元素也到最上边去了.

那么:

当父元素没有高度的时候,如果子元素不浮动,就回按照子元素高度默认撑开.但是当子元素浮动的时候,父元素就不会自动撑开了.(ps:那么一个浮动,一个不浮动呢?)

父组件没了高度这就是高度坍塌,要解决这个问题,我们首先就会想到clear属性,利用clear:both来解决坍塌问题.

clear 属性定义了元素的哪边上不允许出现浮动元素

但是具体清除浮动的方式,我们也有好多种思路:

清除浮动的方法

1. 标签法(不推荐)

<body>
    <div class="father">
        <div class="left">left</div>
        <div class="right">right</div>
        <div class="clear">我是一个标签</div>
    </div>
    <div class="footer">footer</div>
</body>

  <style>
    .father{
        width: 60vw;
        border: 5px solid #000;
    }
    .left{
        width: 30vw;
        height: 200px;
        background: green;
    }
    .right{
        width: 25vw;
        height: 100px;
        background: blue;
    }
    .footer{
        width: 60vw;
        height: 60px;
        background: red;
        border:3px solid rgb(194, 246, 6);
    }
    .clear{
        clear: both;
    }
    </style>
title

当我们的clear元素内容为空时,就可以借助它不允许两边有浮动元素,那么只能放左右div下边的限制来解决高度坍塌的问题.

所以不推荐

2.父级添加overflow属性(不推荐)

通过触发BFC方式,实现清除浮动.

  .fahter{
        width: 60vw;
        border: 5px solid #000;
        overflow: hidden;
    }

这种方式明眼一看很简单,但是会在有些操作时如果不自动换行会直接隐藏掉,最简单的例子比如文字.

未设置overflow

title
设置overflow
title

所以也不推荐

3.使用after伪元素(推荐)

  .father:after{
        content: "";
        display: block;
        clear:both;
    }
    .father{
        ...
        zoom: 1
    }

4.使用before和after双伪元素(推荐)

   .father:after,.father:before{
        content: "";
        display: table;
    }
    .father:after{
        clear: both;
    }
    .father{
        ...
        zoom: 1;
    }

上面清除浮动的方法里面隐约提到触发BFC来达到目的,但是为什么触发BFC就能清除掉浮动呢.

不急,就让我们从Formatting context来慢慢展开.

FC(Formatting context)

BFC

BFC全称是 block formatting context,也就是 块级格式化上下文,是用于布局块级盒的一块 渲染区域。

1. 触发条件

2. 渲染规则

1.3 规则一

这一点其实很好理解.一个接着一个往下排列.

1.3 规则二

我们看个案例。

<body>
    <div style="width:100px;height:100px;background:red;margin:20px;"></div>
    <div style="width:100px;height:100px;background:blue;margin:20px;"></div>
</body>
title

按样式代码来看,红块和蓝块之间间距应该是40px。但实际上是20px。这就是BFC渲染规则的第二点(margin重叠)。

因为BFC的触发条件之一就是根元素,所以body就是一个BFC容器,红块和蓝块是同在body下的相邻块级元素,其margin会生重叠,所以红块和蓝块之间间距只有20px。

1.3 规则三

第三点规则比较难理解我详细解释一下。首先要先理解包含块的含义。

包含块不是一个完整的box,一个完整的box包含margin包含块,border包含块,padding包含块,content包含块。

包含块有可能是box的content包含块,也可能是box的padding包含块。这取决于被包含块所包含的元素的position属性。

例如,如果某个元素position属性是absolute,包含块就是由它的最近的position的值不是 static的父级元素的padding包含块组成。

再例如,如果某个元素的position属性是staticrelative,包含块就是由它的父级元素的content包含块。

如果某个元素的position属性是fixed,包含块就是视口。

那么。BFC中的元素应该与其自身的包含块相接触,而非与BFC相接触,这个包含块有可能是BFC中的一部分,也有可能和bfc无关。

正常元素都是从左往右的格式化,那么对元素的position属性是absolute,right为0,或者元素的float的属性为right,那么就是从右往左的格式化,元素的右边缘和包含块的右边缘接触。

元素H触发生成BFC,其中有两个元素A和元素B,元素A的float的属性为left,那么元素A的左边缘和元素H(也是元素A的包含块)左边缘接触,如果元素B的float的属性也为left,元素B的左边缘不和元素H的左边缘接触,而是和元素A的右边缘接触。这种情况就可以用规则中的“即使包含块中的元素存在浮动也是如此,除非其中元素再生成一个BFC”来解释,元素的float的属性不为none会触发生成BFC,所以这种情况是不矛盾的。

title
1.4 规则四

还是举个例子:

<div>元素A</div>
<div>元素B</div>
title

当你元素A添加float属性后,元素A脱离文档流。

<div style='float:left;'>元素A</div>
<div>元素B</div>

正常情况下,后面元知素B会与前道面的元素A重叠(因为float导致A元素脱离文档流不再占据原来的位置,后面元素会占据前面的位置,如图)

title

这个时候给元素B加上overflow:hidden触发BFC;

<div style='float:left;'>元素A</div>
<div style='overflow:hidden;'>元素B</div>

于是元素B 产生了BFC效果导致元素B收缩,不在占据元素A位置,如图

title

两栏自适应问题的解决方案,有没有!

1.5 规则五

这个规则,可以用来解决内部元素浮动,导致父级元素的高度坍塌问题。其实很好理解,内部元素与外部元素互不影响.

1.6 规则六

也很好理解,高度坍塌问题都解决了,浮动元素的高度肯定要参与BFC的高度计算.

3、应用场景

3.1、清除浮动

在文章最初,提到用clear:both来清除浮动,我们也可以根据BFC的渲染规则第6点(计算BFC容器的高度时,浮动元素也参与计算)来清除浮动,解决高度坍塌的问题。

3.2、解决上下margin边距问题
<body>
    <div style="width:100px;height:100px;background:red;margin:20px;"></div>
    <div style="width:100px;height:100px;background:blue;margin:20px;"></div>
</body>

我们利用BFC渲染规则第2点(属于同一个BFC的两个相邻块级元素的margin会发生重叠),那么不属于同一个BFC的两个相邻块级元素的margin就不会发生重叠。

那么我们在第二个div元素用一个div元素包裹起来,并用overflow:auto触发其BFC。再看一下效果是不是不重叠了。

<body>
    <div style="width:100px;height:100px;background:red;margin:20px;"></div>
    <div style="overflow:auto">
        <div style="width:100px;height:100px;background:blue;margin:20px;"></div>
    </div>
</body>
title
3.3、实现自适应两栏布局

自适应两栏布局,是一个主内容区域和一个侧边栏区域组成,两个区域的宽度都可以随窗口大小自适应。我们就可以利用BFC的规则四来实现这个需求.

详见规则四案例.

4. 关于body元素的小问题

有时候我们在body上设置"display:hidden"不能触发BFC.为什么呢?

w3c规定如果overflow不是visible的块级元素将创建BFC。
但是又有一句提醒除非该值已经扩散到了视口

而w3c对于overflow也有定义:

分析:

  1. html元素的overflow属性默认是visible,并且有body作为子元素,那么body的overflow属性将被用于视窗,产生了扩散行为.
  2. body元素的overflow被设置成了hidden,但是扩散行为导致body元素属性为visible.

所以
所以只能先将html元素的overflow属性设置为hidden,再把body元素的overflow属性设置为hidden,才能使body触发BFC 。

IFC

IFC全称是inline formatting context,也就是 内联格式化上下文,是用于布局内联元素盒子的一块 渲染区域。

1、触发条件

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

2、渲染规则

3、应用场景

FFC

FFC全称是flex formatting context, 也就是 灵活格式化上下文,是用于布局弹性容器的一块 渲染区域。

1、触发条件

父级元素设置display:flex或者`display:inline-flex

2、渲染规则`

可以看阮一峰的Flex 布局教程:语法篇,讲的非常详细。

要注意一点。生成FFC后,其子元素的float、clear和vertical-align属性将失效。

3、应用场景

1、自动撑开页面高度,底栏总是出现在页面的底部
title
<style>
.wrap{
    display:flex;
    padding:0;
    margin:0;
    min-height:100vh;
    flex-direction:column;
}
.main{
    flex-grow:1;
}
</style>
<body class="wrap">
    <header style="line-height:50px;background:red;color:#fff;text-align:center">头部</header>
    <main class="main">内容</main>
    <footer style="line-height:50px;background:#eeeeee;color:#333;text-align:center">底栏</footer>
</body>
title
2、经典的圣杯布局
<style>
.wrap {
    display: flex;
    padding: 0;
    margin: 0;
    min-height: 100vh;
    flex-direction: column;
}
header,
footer {
    flex: 0 0 50px;
}

.content {
    display: flex;
    flex: 1
}

.main {
    flex: 1;
}
.nav,
.ads{
    flex: 0 0 100px;
    background:green;
}
.nav{
    order:-1;
    background:yellow;
}
</style>
<body class="wrap">
    <header style="line-height:50px;background:red;color:#fff;text-align:center">头部</header>
    <div class="content">
        <main class="main">内容区</main>
        <nav class="nav">侧边导航</nav>
        <aside class="ads">侧边栏</aside>
    </div>
    <footer style="line-height:50px;background:#eeeeee;color:#333;text-align:center">底栏</footer>
</body>
title

GFC

GFC全称是gridLayout formatting context,也就是 网格布局格式上下文,是用于布局网格容器的一块 渲染区域。

1、触发条件

当为一个元素设置display值为grid的时候,此元素将会获得一个独立的渲染区域,我们可以通过在网格容器(grid container)上定义网格定义行(grid definition rows)和网格定义列(grid definition columns)属性各在网格项目(grid item)上定义网格行(grid row)和网格列(grid columns)为每一个网格项目(grid item)定义位置和空间。

2. 应用场景

那么GFC有什么用呢,和table又有什么区别呢?首先同样是一个的表格,但GridLayout会有更加丰富的属性来控制行列,控制对齐以及更为精细的渲染语义和控制。

最后:关于zoom知识的扩展
zoom:1是针对ie的属性,可以激活hasLayout属性,关于hasLayout

haslayout 是Windows Internet Explorer渲染引擎的一个内部组成部分。在InternetExplorer中,一个元素要么自己对自身的内容进行计算大小和组织,要么依赖于父元素来计算尺寸和组织内容。为了调节这两个不同的概念,渲染引擎采用了 hasLayout 的属性,属性值可以为true或false。当一个元素的 hasLayout属性值为true时,我们说这个元素有一个布局(layout)

要想更好的理解 css, 尤其是 IE 下对 css 的渲染,haslayout 是一个非常有必要彻底弄清楚的概念。大多IE下的显示错误,就是源于 haslayout。如果它设置成了true,它就不得不去渲染它自己,因此元素不得不扩展去包含它的流出的内容。例如浮动或者很长很长的没有截断的单词,如果haslayout没有被设置成true,那么元素得依靠某个祖先元素来渲染它。这就是很多的ie bugs诞生的地方。

参考文章:
红尘炼心-四年前端在CSS面试上跪了

上一篇下一篇

猜你喜欢

热点阅读