前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >了解BFC特性,轻松实现自适应布局

了解BFC特性,轻松实现自适应布局

作者头像
Maic
发布2022-07-28 12:29:32
6670
发布2022-07-28 12:29:32
举报
文章被收录于专栏:Web技术学苑

BFC(Block Formatting Context)俗称块级格式上下文,初次看到这词似乎有点不是很理解,通俗解释就是一个独立区域决定了内部元素的排放,以及内部元素与外部元素的相互作用关系

正文开始...

BFC是什么

俗称块级格式上下文,一块独立的区域决定了内部元素的位置排列,以及内部元素与外部元素的作用关系

BFC特点

我们先了解下BFC有什么特点

1、垂直方向,相邻BFC的块级元素会产生外边距合并

2、BFC包含浮动元素,浮动会触发新的BFC产生

3、已经确定的BFC区域不会与相邻BFC的浮动元素边距发生重合

针对以上几点我们来具体深究一下BFC的特性到底有何区别,在什么样的场景下会比较触发BFC

新建一个index.html测试

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>BFC</title>
  <style>
    *{
      padding: 0;
      margin: 0;
    }
    .wrap-box {
      width: 300px;
    }
    .inner-box {
      width: 100px;
      height: 50px;
    }
    .inner-box:nth-of-type(2n+1) {
      background-color: red;
    }
  </style>
</head>
<body>
  <div class="wrap-box">
      <div class="inner-box">1</div>
      <div class="inner-box">2</div>
      <div class="inner-box">3</div>
  </div>
</body>
</html>

不出意外在wrap-box这个BFC中,内部元素垂直单行排列

这说明块级格式上下文,在wrap-box这个元素决定了内部的元素排放,因为子元素始终是被包裹起来的,因为是块级元素,所以单行排列。

接下来我们将子元素添加外边距margin:10px 0;

代码语言:javascript
复制
*{
    padding: 0;
    margin: 0;
 }
.wrap-box {
   width: 300px;
}
.inner-box {
   width: 100px;
   height: 50px;
   margin: 10px 0;
}

另外我们看下wrap-box的盒子模型

在子元素inner-box我们加了外边距margin,我们从已知的BFC特点知道相邻的BFC外边距会合并。

因为被包裹的inner-box是三个块级元素,在wrap-box内部来说,这三个内部div形成独立的BFC,所以相邻的1-2,2-3的外边距就合并了。

现在我有个需求,我不想让他们合并,我要破坏内部的三个BFC结构怎么办?

因此我需要将第二个inner-box改造成一个新的BFC结构

代码语言:javascript
复制
<div class="wrap-box">
      <div class="inner-box">1</div>
      <div class="inner-box-2">
        <div class="inner-box">2</div>
      </div>
      <div class="inner-box">3</div>
  </div>

注意我在第二个元素多加了一层结构 因此结构变成下面这样,主要看第三个图,我用虚线标出了表明第二元素已经被加了一层结构,貌似外边距还是会合并,这是为啥?

从新的结构我们可以知晓,相邻块级元素的BFC会使边距发生合并,以前的内部的BFC是123,现在新的BFC是143,2已经被4包裹独立出来了,在2内部的margin会作用到父级,从而作用到父级相邻的BFC结构。

我们继续在4上添加一个margin:10px 0,神奇的事情发生了,居然还是一样边距被合并了,具体看下代码

代码语言:javascript
复制
 .wrap-box {
      width: 300px;
}
.inner-box {
      width: 100px;
      height: 50px;
      margin: 10px 0;
      overflow: hidden;
}
.inner-box:nth-of-type(2n+1) {
      background-color: red;
 }
.inner-box-2 {
  margin: 10px 0;
}

你会发现居然在2的外层加了magrin,居然不会影响整个盒模型的高度。

因此你再细品那句话相邻块级格式上下文的上下边距会产生重叠,于是你恍然大悟,143是三个BFC结构,所以4设置margin自然就被重合了。

但是我要破坏这种相邻BFC结构,因此触发BFC结构的机会来了。我给inner-box-2加个样式,用overflow:hidden触发生成一个新的BFC;

现在就变成了这样了

没错,盒子模型高度变成了190了,中间的4外边距没有合并了。

由于在4不是虽然不是根元素,但是身上加了overflow:hidden触发4形成一个新的BFC,那么触发BFC还有其他什么方式吗?

我们了解到除了overflow:hidden,还有以下几种方式 overflow: auto;display: flex; display: table;display: -webkit-box; float: left;

代码语言:javascript
复制
 .inner-box-2 {
  margin: 10px 0;
  overflow: hidden;
  /* overflow: auto; */
  /* display: flex; */
  /* display: table; */
  /* display: -webkit-box; */
  /* float: left; */
}
已经确定的BFC不会与相邻浮动的BFC边距发生重合

当我们把inner-box-2设置为浮动后,边距就不会合并了。这也证实了相邻BFC与已经设置的浮动元素边距并不会合并,但inner-box-2inner-box-1始终在一个大的BFC包裹着,而每一个自身元素又形成一个独立的BFC

代码语言:javascript
复制
  <div class="wrap-box">
      <div class="inner-box inner-box-1">1</div>
      <div class="inner-box inner-box-2">2</div>
  </div>
代码语言:javascript
复制
 <style>
    *{
      padding: 0;
      margin: 0;
    }
    .wrap-box {
      width: 300px;
      border: 1px solid #111;
      overflow: hidden;
    }
    .inner-box {
      width: 100px;
      height: 50px;
      margin: 10px 0;
      overflow: hidden;
    }
    .inner-box-2 {
      float: left;
    } 
    .inner-box:nth-of-type(2n+1) {
      background-color: red;
    }
    .inner-box:nth-of-type(2n) {
      background-color: yellow;
    }
  </style>
探索BFC九宫格布局

我们知道相邻的BFC结构垂直方向外边距会合并,利用这点,我们实现九宫格布局

代码语言:javascript
复制
 <div class="wrap-box">
      <div class="inner-box">1</div>
      <div class="inner-box">2</div>
      <div class="inner-box">3</div>
      <div class="inner-box">4</div>
      <div class="inner-box">5</div>
      <div class="inner-box">6</div>
      <div class="inner-box">7</div>
      <div class="inner-box">8</div>
      <div class="inner-box">9</div>
  </div>

对应的css如下

代码语言:javascript
复制
 *{
      padding: 0;
      margin: 0;
    }
    .wrap-box {
      width: 300px;
      border: 1px solid #111;
      display: flex;
      flex-wrap: wrap;
    }
    .inner-box {
      width: 100px;
      height: 50px;
      margin: 10px 0;
      overflow: hidden;
      float: left;
    }
    .inner-box:nth-of-type(2n+1) {
      background-color: red;
    }
    .inner-box:nth-of-type(2n) {
      background-color: yellow;
    }

注意我们给所有的子元素加了浮动,那么此时会造成父元素高度坍塌,因此父级元素必须要加上overflow:hidden或者设置display: inlie-block或者position: absolute;这样才可以导致父级元素不坍塌。

貌似456中间元素因为设置浮动破坏了BFC,所以我们需要给456设置特殊margin才行,于是乎你给456加一层div,然后设置margin: -10px 0并且要设置左浮动

代码语言:javascript
复制
  .item-2 {
      float: left;
      margin: -10px 0;
    }
代码语言:javascript
复制
 <div class="wrap-box">
      <div class="inner-box">1</div>
      <div class="inner-box">2</div>
      <div class="inner-box">3</div>
      <div class="item-2">
        <div class="inner-box">4</div>
        <div class="inner-box">5</div>
        <div class="inner-box">6</div>
      </div>
      <div class="inner-box">7</div>
      <div class="inner-box">8</div>
      <div class="inner-box">9</div>
  </div>

OK已经可以了

此时我们这样改dom结构似乎有点不是很好,因为可能数据是从后端接口返回并不是写死的数据结构,因此我们再改下结构布局

代码语言:javascript
复制
 <div class="wrap-box">
      <div class="item">
        <div class="inner-box">1</div>
        <div class="inner-box">2</div>
        <div class="inner-box">3</div>
      </div>
     
      <div class="item">
        <div class="inner-box">4</div>
        <div class="inner-box">5</div>
        <div class="inner-box">6</div>
      </div>
    <div class="item">
      <div class="inner-box">7</div>
      <div class="inner-box">8</div>
      <div class="inner-box">9</div>
    </div>
  </div>
代码语言:javascript
复制
  *{
      padding: 0;
      margin: 0;
    }
    .wrap-box {
      width: 300px;
      border: 1px solid #111;
      overflow: hidden;
    }
    .inner-box {
      width: 100px;
      height: 50px;
      overflow: hidden;
      float: left;
    }
    .inner-box:nth-of-type(2n+1) {
      background-color: red;
    }
    .inner-box:nth-of-type(2n) {
      background-color: yellow;
    }
    .item {
      margin: 10px 0;
      overflow: hidden;
    }

我们最初把margin作用在每个小元素下,现在我们利用BFC的特性,我们把margin作用在item上,因为三个item就是相邻垂直方向的BFC结构,边距会产生合并,也正是利用边距合并巧妙的解决了保持边距相等的问题。

具体可以看下效果

由于不同的布局方式,因此写出来的页面拓展性是完全不一样,拓展性强的布局方式,对于后期的维护是相当有益。因此不推荐第一种方式改结构,然后特殊设置456的父边距,虽然效果能达到一致,但是后期维护性与拓展性不高。

BFC实现自适应布局

有时候左侧固定,右侧自适应这种页面结构时常会有,这种布局方案有哪些可以实现呢

代码语言:javascript
复制
 <h1>左边固定,右边自适应,右边随着左边的宽度而自适应</h1>
  <div class="wrap-box">
      <div class="slide-left">left</div>
      <div class="main">main</div>
  </div>

对应的css

代码语言:javascript
复制
 *{
      padding: 0;
      margin: 0;
    }
    .wrap-box {
      width: 300px;
      border: 1px solid #111;
      overflow: hidden;
      resize:horizontal;
    }
    .slide-left {
      width: 100px;
      height: 100px;
      background-color: red;
     
    }
    .main {
      height: 100px;
      background-color: yellow;
    }

此时发现页面不尽人意,肯定是下面这样的

但是当我们给slide-left设置float:left后,我们会发现,此时slide-left的文档流被破坏,main会紧贴着slide-left排列

代码语言:javascript
复制
.slide-left {
      width: 100px;
      height: 100px;
      background-color: red;
      resize:horizontal;
      float: left
    }

此时我们可以观察到main贴着slide-left,宽度就是父级的宽度

但实际上main是需要剩下的宽度,他需要根据左侧的slide-left的宽度而自适应 因此你可以,让main成为一个独立BFC,我们需要设置它oveflow:hidden就行 那么此时就会变成

完整的css如下

代码语言:javascript
复制
   *{
      padding: 0;
      margin: 0;
    }
    .wrap-box {
      width: 300px;
      border: 1px solid #111;
      overflow: hidden;
      resize:horizontal;
    }
   .slide-left {
      width: 100px;
      height: 100px;
      background-color: red;
      float: left;
    }
  .main {
      height: 100px;
      background-color: yellow;
      overflow: hidden;
    }

OK,现在就实现了右侧根据左侧宽度的大小自适应了。

更多关于BFC可以参考MDN BFC[1]

总结
  • 了解什么是BFC,BFC简称块级格式上下文,它是一块独立的区域影响子元素的排列,相邻区域的BFC边距会产生重合
  • 触发BFC条件有,display: flexdisplay: inline-blockdisplay:box,position:absolute,或者oveflow: hidden/auto,float:left;
  • 利用BFC实现九宫布局,本质利用相邻BFC外边距合并
  • 左侧固定,右侧自适应布局
  • 本文 code example[2]

参考资料

[1] MDN BFC: https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context

[2] code example: https://github.com/maicFir/lessonNote/tree/master/html/02-BFC%E8%A7%A6%E5%8F%91

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Web技术学苑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • BFC是什么
  • BFC特点
  • 已经确定的BFC不会与相邻浮动的BFC边距发生重合
  • 探索BFC九宫格布局
  • BFC实现自适应布局
  • 总结
  • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档