别再瞎改浮动!BFC 专治布局各种疑难杂症

0 阅读6分钟

引言

  在前端CSS布局里,浮动绝对是又爱又恨的存在!日常做图文混排、多列布局都离不开它,但只要开启浮动,高度塌陷、布局错乱、边距重叠等奇葩bug就会接踵而至,让不少新手头疼不已。其实这些问题都不是bug,而是浮动的特性导致的!而BFC就是CSS官方自带的布局神医,专门专治浮动引发的各类布局疑难杂症。不用啃枯燥的官方文档,也不用死记硬背晦涩规则

一、文档流

  在讲浮动定位之前,我们要先了解什么是文档流。文档流就是浏览器在渲染页面时,会遵照从上往下,从左往右,依次排列,这种页面的排板方式就是文档流

二、浮动布局

  那什么是浮动布局呢?他最初被官方创建出来的意义是文字环绕,用一张图解释一下什么是文字环绕:

image.png

  如图所示,图片被周边文字环绕排布。实现原理十分简单:只需给<img>图片标签添加 float: left 样式,即可快速实现图文混排的文字环绕效果。

<style>
    img{
        float: left;
    }
</style>
<body>
    <div class = "page">
        <img width="200" src="https://ts1.tc.mm.bing.net/th/id/OIP-C.ZjqbZElwdeux67YIjN1tkgHaEK?cb=thfc1falcon&rs=1&pid=ImgDetMain&o=7&rm=3" alt="">
        <p>
            &emsp;&emsp;不少前端小伙伴写 JS 时总被数据类型坑:null被 typeof 错判成对象、数组识别为 Object,原生数值用 instanceof 判断屡屡出错,面试还总被深挖底层原理。本文细数 JS
            全部数据类型,详解三种常用校验方式的优缺点与底层逻辑,搭配实操案例帮你按需选型,轻松避开类型判断各类 bug。
            作者:咪饭只吃一小碗
            链接:https://juejin.cn/post/7646480731196375091
            来源:稀土掘金
        </p>
    </div>
</body>

  使用浮动定位会让元素脱离标准文档流—— 虽然它不会覆盖文字,但当页面中存在其他容器时,很容易引发父容器高度塌陷问题,最终直接影响后续元素的正常排版与布局。举个例子:


  <style>
    *{
      margin: 0;
      padding: 0;
    }
    .item{
      width: 200px;
      height: 100px;
      float: left;
    }
    .item:nth-child(1) {
      background-color: #ed4949;
    }
    .item:nth-child(2) {
      background-color: #dfef26;
    }
    .item:nth-child(3) {
      background-color: #5df13c;
    }
  </style>
</head>
<body>
  <ul>
    <li class="item">1</li>
    <li class="item">2</li>
    <li class="item">3</li>
    <!-- <div class = "clear"></div> -->
  </ul>
  <h2>Hello world</h2>
</body>
</html>

  运行结果如下:

image.png

  我们希望把 hello world 显示在三个小方块的正下方,可问题在于:这三个方块都设置了浮动,导致它们脱离了文档流,最终引发父容器高度塌陷。而我们并不希望后面的内容受到浮动影响,那该怎么清除浮动带来的负面影响呢?接下来,我就为大家讲解几种常用的清除浮动方法。

三、清除浮动的负面效果

 3.1. 直接给父容器设置高度

  站在上帝视角分析,直接给 ul 固定高度 height: 100px 确实能临时修复塌陷问题、实现预期布局,但这种硬编码写死高度的方式,并不符合前端工程化的开发思路。并不推荐这种方法。

ul{
   height: 100px;
} 

 3.2 在浮动元素的末尾增加一个空容器,设置一个 clear : both

  就像这样:

  <style>
    .clear{
        clear: both;
    } 
  </style>
<body>
  <ul>
    <li class="item">1</li>
    <li class="item">2</li>
    <li class="item">3</li>
    <div class = "clear"></div>
  </ul>
  <h2>Hello world</h2>
</body>

  该方案虽能清除浮动,倘若项目里有上百处浮动布局,就要凭空新增上百个空 div,DOM 冗余严重、加重页面渲染负担,实际开发不推荐。

 3.3 为父容器设置 after 伪元素,在伪元素上 clear : both

  就像这样:

  <style>
    ul::after{
      content: '';
      clear: both;
      display: block;
    } 
  </style>
<body>
  <ul>
    <li class="item">1</li>
    <li class="item">2</li>
    <li class="item">3</li>
  </ul>
  <h2>Hello world</h2>
</body>

  这种方式就很好的解决浮动的负面效果,且不会产生冗余 DOM、增加页面渲染损耗,是开发中值得推荐的清浮动方案。

 3.4 给被影响的元素设置 clear: both;

  就像这样:

  <style>
    h2{
      clear: both;
    } 
  </style>
<body>
  <ul>
    <li class="item">1</li>
    <li class="item">2</li>
    <li class="item">3</li>
  </ul>
  <h2>Hello world</h2>
</body>

  这样也可以达到我们想要的结果,但是我们还是不推荐,因为这不符合程序员写代码的逻辑,最好是父容器内部的矛盾问题,就在父容器里面自己解决,而非修改后续兄弟元素的样式。

 3.5 将父容器设置为 BFC 容器

  这最后一种方法也是全文的重中之重,只需把浮动元素的父级容器触发为 BFC 独立渲染区域,既能自动撑开父盒子高度、解决高度塌陷,从根源隔绝浮动对外层与后续兄弟元素的布局干扰,无需新增冗余 DOM 标签,也不用改动页面其他元素样式。

四、BFC容器

  在 HTML 布局中,一直存在一个经典问题:父子元素的 margin-top 会发生重叠(外边距塌陷) 。我们直接用代码来直观理解:

<style>
    .parents{
        width: 100%;
        height: 500px;
        background-color: green;
        margin-top: 100px;
    }
    .child{
        width: 100%;
        height: 200px;
        background-color: rgb(255, 0, 200);
        margin-top: 50px;
    }
</style>
<body>
    <div class = "parents">
        <div class = "child">
        </div>
    </div>
</body>

  运行结果如下:

image.png

  图中绿色是父容器,粉色是子容器。按照正常逻辑,子容器设置了 margin-top: 50px,应该距离父容器顶部 50px 才对。但实际效果却是:子元素直接带着父元素一起往下跑,两者的外边距合并在了一起。这就是典型的margin 重叠问题,而 BFC 正是专门用来解决这类布局 bug 的核心机制。

4.1 BFC 的渲染规则

  1. BFC 容器内部的子元素也是从上往下,从左往右排列
  2. BFC 容器是一个独立的拥有特殊渲染规则的容器,它内部的子元素不会影响外部
  3. BFC 容器在计算高度的时候,会将浮动的子元素的高度也计算在内

4.2 如何创建一个 BFC 容器

给元素添加以下任意一种 CSS 属性,即可生成 BFC 容器:

  1. overflow: hidden || auto || overlay || scroll;
  2. position: absolute || fixed
  3. float: left || right
  4. display: flex || grid || inline-xxxx;

五、总结

  • 浮动初衷:实现文字环绕图文效果,浮动元素会脱离标准文档流
  • 浮动副作用:造成父容器高度塌陷,打乱页面正常布局
  • 清除浮动(不推荐):固定父级高度、新增空div、给后续元素清浮动
  • 清除浮动(推荐) :父级after伪元素清浮动、父容器开启BFC
  • BFC作用:独立渲染区域,解决浮动高度塌陷、父子margin外边距重叠问题
  • BFC渲染规则:内部正常排列、内外布局互不干扰、计算高度包含浮动元素
  • 触发BFC方式:overflow非visible、绝对/固定定位、设置浮动、flex/grid/行内块等display属性