一文摸透从文档流,到盒子模型,再到BFC和它的亲朋好友

534 阅读7分钟

前言

这个男人叫小帅,哦不,这个玩意叫BFC,虽然你可能不认识它,但是在你写HTML时,已经其实已经遵循它的“规则”办事了,当然除了BFC,我们还需要知道其他的“规则”,这样我们就更容易去布置好看的界面。

下面我们将深入探讨文档流、盒模型、显示类型转换、块格式化上下文(BFC)及其与其他格式化上下文(如弹性布局上下文FFC和网格布局上下文GFC)的关系,并通过具体代码示例来帮助理解。

文档流与布局基础

HTML文档中的元素按照从上到下、从左到右的方式自然排列,形成所谓的“文档流”。默认情况下,块级元素(例如<div><p>等)会垂直堆叠,而行内元素(如<span><a>等)则在同一行内水平排列。这种简单的排列方式构成了网页的基本布局框架。

代码:


<body>
        <p>我是块级元素,我独占一行</p> <!-- 块级元素 -->
        <p>我也是块级元素,我独占一行</p> <!-- 块级元素 -->
        <span>我是行内元素</span><span>我也是行内元素</span> <!-- 行内元素 -->
</body>

图示: image.png

了解上面这些,你是否有疑问呢?块级就一定是块级吗?行内元素就一定是块级吗?能否转换呢?

显示类型与转换

元素的显示类型决定了它在文档流中的行为。主要分为:

  • 块级元素 (block) :占据一行并可以设置宽高。
  • 行内元素 (inline) :不打断文本流且不能直接设定宽度或高度。

比如:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
   <style>
     *{
        margin: 0;
        padding: 0;
    }

    div{
        width: 100px;
        height: 100px;
        border: 1px solid red;
        padding: 10px 20px;
         display: inline; 
    }

    span{
        width: 100px;
        height: 100px;
        background-color: green;
         display: block; 
    }
   </style>
</head>

<body>
    <div>我是块级元素</div>
    <span>我是行内元素</span>
    <span>我也是行内元素</span>
</body>
</html>

图示:

image.png 通过CSS display属性,可以改变元素的显示类型,我们这个例子中,就将块级变成了行内元素,行内变成块级元素,

  • 行内元素的长宽大小不能设置,由内容支撑,
  • 而块级元素的长宽是可以直接设置的

下面我们来看看盒子模型:

盒模型与尺寸计算

每个HTML元素都被视为一个矩形盒子,它由内容区、内边距(padding)、边框(border)和外边距(margin)组成。根据CSS规范,有两种不同的盒模型:

  • 标准盒模型 (content-box) :宽度和高度仅适用于内容区域,默认为标准盒模型。
  • IE盒模型 (border-box) :宽度和高度包括了内容、内边距和边框。

可以通过设置box-sizing属性来选择使用哪种盒模型: 代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>一个盒子,自己的规则</title>
</head>
<style>
 
     /* 盒模型 + 块级 */
    .box,.box2,.box3{
       width: 100px;
       height: 100px;
       padding: 10px;
       border: 1px solid red;
       background-color: green;
    }
   
    .box2{
        /* border:  以内盒子的大小 IE 怪异盒模型 */
        box-sizing: border-box;
    }

    .box3{
        /* 默认值,标准盒模型 w h content的大小 */
        box-sizing: content-box;
    }
</style>
<body>
    <div class="box"></div>
     <div class="box2"></div>
     <div class="box3"></div>
    
</body>
</html>

图示: image.png 结果: 由图可知,在其他相同的前提下,因为设置了不同的 box-sizing,得到了两个不同的盒模型,两种盒模型的计算规则如下:

  • 标准盒模型 (content-box)
    • 实际宽度 = width + padding-left + padding-right + border-left-width + border-right-width
    • 实际高度 = height + padding-top + padding-bottom + border-top-width + border-bottom-width
  •  IE盒模型 (border-box)
    •   内容宽度 = width - (padding-left + padding-right + border-left-width + border-right-width)

    • 内容高度 = height - (padding-top + padding-bottom + border-top-width + border-bottom-width)

深入BFC之中

在HTML文档中,根元素(即<html>标签)本身就是一个顶级BFC,它为整个页面提供了一个基本的布局框架。就像建筑中的地基一样,这个顶级BFC确保了页面内的所有内容都遵循一定的布局规则。具体的元素排列和布局则由更细致的CSS属性控制,如浮动、定位和弹性盒子等。因此,即便你不显式地创建BFC,实际上也在利用BFC的基本特性来组织页面内容。 那么BFC有什么用,能干什么,怎么创建BFC呢?

我的这个文章有讲到作用和创建: 当CSS中子元素浮动起来后导致父元素高度为空,该怎么解决?😬😬=-=在课堂上,老师提到了关于父元素高度塌陷的问题。现 - 掘金

现在我来补充一下:

重叠的易错点:

代码: 这段代码创建了的BFC,实现了边距不重叠的作用。

案例一:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BFC</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .box{
         width: 200px;
         height: 200px;
         background-color: lightblue;   
         border: 1px solid red;
        }
        .box1{
         margin-bottom: 50px;
        }
        .box2{
         margin-top: 30px;
        }



    </style>
</head>
<body>
    <div class="box box1">Box1</div>
    <div style="overflow: hidden;">
    <div class="box box2" ></div>
    </div>
</body>
</html>

案例二:

当我们小小的更改一下,将样式写入box2中时,创建这个新的BFC,对于防止边距的重叠就没有起到作用。你知道为什么吗?

<body>
    <div class="box box1">Box1</div>

    <div class="box box2" style="overflow: hidden;"></div>
    
</body>

案例分析:

案例二中:

尽管为.box2添加了overflow: hidden来创建新的BFC,但由于.box1.box2依然是相邻的兄弟元素,并且它们同属一个父级BFC(即<body>),因此它们之间的外边距仍然会发生折叠。

案例一中:

通过将.box2放入一个新的容器并在该容器上设置overflow: hidden,我们创建了一个新的BFC。这样做的好处是,.box1.box2不再处于同一个BFC内,从而避免了它们之间外边距的折叠现象。这种做法有效地隔离了两个盒子,使得它们的布局行为更加独立。

图解:

如此就很清晰了 image.png

独特的渲染空间:

代码 通过BFC,开辟一个新的空间位置

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
  .container {
    border: 2px solid black;
    padding: 10px;
}

.float-box {
    float: left;
    width: 150px;
    height: 100px;
    background-color: lightblue;
    margin: 10px;
}

.bfc-box {
    width: 300px;
    height: auto;
    background-color: lightgreen;
    overflow: auto; /*创建 BFC  切换*/
    padding: 10px;
    border: 1px solid #ccc;
}
  </style>
</head>
<body>
  <div class="container">
    <div class="float-box">这是一个左浮动的盒子</div>
    <div class="bfc-box">
        <p>这是创建了 BFC 的盒子内部的内容。</p>
        <p>注意,这个内容不会被外部的浮动元素影响。</p>
        <p>注意,这个内容不会被外部的浮动元素影响。</p>
        <p>注意,这个内容不会被外部的浮动元素影响。</p>
        <p>注意,这个内容不会被外部的浮动元素影响。</p>
        <p>注意,这个内容不会被外部的浮动元素影响。</p>
    </div>
  </div>
</body>
</html>

创建独立的渲染区域(BFC)

通过设置 .bfc-boxoverflow: auto;,创建了一个新的BFC。这意味着:

  • 隔离内部布局.bfc-box 内部的元素布局与外部元素完全隔离,不受外部浮动元素的影响。
  • 防止浮动溢出:即使 .float-box 是一个浮动元素,它也不会超出 .bfc-box 的边界,确保父容器能够正确包裹浮动元素。

图解:

这就是有没有BFC是区别所在 PixPin_2024-12-29_16-41-55.gif

BFC的亲朋好友:GFC、FFC

我们简单介绍一下GFC和FFC:

GFC

是CSS Grid布局的一部分,它定义了一个新的块级格式化上下文,类似于BFC(Block Formatting Context),但专门为网格布局设计。当一个元素被设置为display: griddisplay: inline-grid时,它就会创建一个新的GFC,在这个上下文中,子元素(即网格项)将遵循CSS Grid布局规则进行排列。

简单用法:

image.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
<style>
    *{
        margin: 0;
        padding: 0;
    }
    .grid-container {
    display: grid;
    grid-template-columns: auto auto auto; /* 三列等宽 */
    gap: 10px; /* 单元格之间的间隔 */
    padding: 10px; /* 网格容器的内边距 */
}

.grid-item {
    background-color: rgba(255, 255, 255, 0.8);
    border: 1px solid rgba(0, 0, 0, 0.8);
    padding: 20px;
    font-size: 30px;
    text-align: center;
}

.item1 { background-color: red; }
.item2 { background-color: orange; }
.item3 { background-color: yellow; }
.item4 { background-color: green; }
.item5 { background-color: blue; }
.item6 { background-color: indigo; }
.item7 { background-color: violet; }
.item8 { background-color: pink; }
.item9 { background-color: brown; }
</style>
</head>

<body>
    <div class="grid-container">
        <div class="grid-item item1">1</div>
        <div class="grid-item item2">2</div>
        <div class="grid-item item3">3</div>
        <div class="grid-item item4">4</div>
        <div class="grid-item item5">5</div>
        <div class="grid-item item6">6</div>
        <div class="grid-item item7">7</div>
        <div class="grid-item item8">8</div>
        <div class="grid-item item9">9</div>
    </div>
</body>
</html>

FFC

是CSS中一种用于布局的上下文,它由设置了display: flexdisplay: inline-flex属性的容器创建。在这种上下文中,直接子元素被称为“弹性项”(flex items),它们会遵循Flexbox布局规则进行排列和对齐。

下面是一个简单的例子: image.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .flex-container {
            display: flex;
            justify-content: space-around; /* 水平居中 */
            align-items: center; /* 垂直居中 */
            height: 300px; /* 容器高度 */
            background-color: lightgray;
        }

        .flex-item {
            width: 100px;
            height: 100px;
            background-color: tomato;
            margin: 5px;
            text-align: center;
            line-height: 100px; /* 让文本垂直居中 */
            color: white;
        }
    </style>
</head>
<body>
    <div class="flex-container">
        <div class="flex-item">1</div>
        <div class="flex-item">2</div>
        <div class="flex-item">3</div>
    </div>
</body>
</html>

最后:

本文讲的有点杂乱,得结合之前的一篇文章,就当作是我最近学习的总结。 如果有问题也请指出,谢谢。