前端必备CSS之位置篇(文档流、定位与浮动)

256 阅读22分钟

前言

作为前端开发,常常要控制页面的元素位置摆放,而文档流、定位、浮动就是这方面绕不开的核心。当然,浮动已经基本上弃用了,但是还是要懂一些的,毕竟“有剑不用”和“无剑可用”是两回事,万一有情况要用到浮动呢。接下来,我们就来深入探讨一下它们的妙用。

一、前置知识:文档流(普通流)

想要讲解定位与浮动,就必须讲解一下文档流是什么。不然在讲述脱离文档流时,你会“只知其然,不知其所以然”。

什么是文档流?

文档流的本质就是HTML页面中元素的默认排序规则,它又叫普通流。

  • 举例: 想象一下,我们在纸上写文章时,文字会从左到右、从上到下依次排列,换行后继续按顺序书写。
    • 这就是 "流" 的概念。在 CSS 中,文档流(Normal Flow)  就是元素在页面中默认的排列规则:元素按照 HTML 结构的顺序,遵循一定的规则 "排队",形成页面的基础布局。

文档流中的元素分类

文档流的排列规则,会根据元素的类型(块级 / 行内 / 行内块)有所不同:

块级元素(block-level)

特点是 "独占一行",默认宽度为父元素的 100%,高度由内容撑开,排列顺序从上到下。常见的块级元素有divph1-h6ulli等。

  • 举例: 一个div会默认占满父元素的宽度,后面的元素会自动换行到下一行。

    块级元素.jpg

        <!-- 块级元素:独占一行,宽度默认100%,高度由内容决定 -->
        <div style="border: 2px solid #f00; margin: 5px; padding: 10px;">
            我是块级元素 div(内容少)
        </div>
        <div style="border: 2px solid #0f0; margin: 5px; padding: 10px;">
            <p>我是另一个块级元素 div</p>
            <p>(内容多一点,高度会被撑开)</p>
        </div>
    

行内元素(inline)

特点是 "同行排列",宽度和高度由内容撑开,不会独占一行。排列顺序从左到右,相邻元素会在同一行依次排列,直到一行放不下才换行。常见的行内元素有spanaimg(特殊行内块)、strong等。

  • 举例: 多个span会在一行内从左到右排列,内容超宽后自动折行。

    行内元素.jpg

        <!-- 行内元素:同行排列,宽高由内容决定,超宽自动折行 -->
        <div style="border: 1px solid #ccc; padding: 10px; width: 300px;">
            <span style="background: #ffeeee; padding: 5px; margin: 2px;">行内元素1</span>
            <span style="background: #eeeeff; padding: 5px; margin: 2px;">行内元素2(这段内容很长,会触发自动折行)</span>
        </div>
    

行内块元素(inline-block)

兼具行内元素和块级元素的特点:可以同行排列(像行内元素),但可以设置宽高(像块级元素)。imginput是典型的行内块元素。

  • 举例: 通过display: inline-block可以将块级元素以及行内元素转换为行内块元素;还有一些元素天生就是行内块元素,拥有inline-block特性,比如说<input><img><button><select> 等表单元素或替换元素。

    行内块元素.jpg

        <!-- 行内块元素:同行排列,可设置宽高 -->
        <div style="border: 1px solid #ccc; padding: 10px;width: 600px;">
            <div
                style="display: inline-block; width: 100px; height: 60px; background: #faa; margin: 5px; text-align: center; line-height: 60px;">
                行内块1
            </div>
            <div
                style="display: inline-block; width: 180px; height: 160px; background: #afa; margin: 5px; text-align: center; line-height: 160px;">
                行内块2(自定义宽高)
            </div>
            <input type="text" style="margin: 5px;width: 150px; height: 60px;" placeholder="input是天然行内块">
        </div>
    

打破规则

在默认状态下,元素会严格遵循文档流规则排列,不会重叠,也不会随意改变位置。如果想打破这种 "自然状态",就需要用到定位浮动—— 这也是它们存在的核心意义:改变元素在文档流中的默认行为

二、定位(Position)

定位的核心是通过position属性,改变元素在文档流中的位置,甚至让元素 "脱离文档流"position有 5 个常用值,我们将逐一解析:

1. static(静态定位)

position: static是所有元素的定位默认值,代表元素遵循文档流的排序规则。此时topbottomleftrightz-index属性无效(设置了也不会生效)。

  • 定位参考系: 因为默认定位是遵循文档流的排序规则,所以没有参考系。
  • 比喻: 用比喻的形式更容易记住,如果要形容的话,默认定位就像乖乖排队的良好市民,不做任何与排队无关的事。

示例

可以从下图中看出盒子模型2(默认定位)即使被设置向右偏移,也没有生效,仍处于原位置。

  • 示图:

    默认定位.jpg

  • 示例代码:

    .box1 {
        /* 相对定位 */
        position: relative;
        right: -50px;
        background-color: green;
    }
    
    .box2 {
        /* 默认定位 */
        /* position: static; */
        right: -50px;
        background-color: yellow;
    }
    
    <div class="box1">
        盒子模型1(相对定位)
    </div>
    <div class="box2">
        盒子模型2(默认定位)
    </div>
    

2. relative(相对定位)

position: relative使得该元素虽然开启了定位,但是仍在文档流之中,并且它的原有位置会被保留(其他元素不会抢占原位置,不影响其他元素的排列)

  • 定位参考系: 相对定位的元素用其原有位置作为参照点,通过改变它与其参考系的各方向上的距离,从而改变它的布局位置。
  • 比喻: 相对定位就像排队时不耐烦地挪了一下脚(根据情况,这一挪也可以很大),一条腿偏离了原位置,但是另一条腿仍然占着原位置,别人不能插队。
  • 关键属性: 通过topbottomleftright表示元素边缘相对于自身原始位置边缘的偏移距离
    • top: 相对于自身原位置的顶部的偏移距离。
    • bottom: 相对于自身原位置的底部的偏移距离。
    • left: 相对于自身原位置的左侧的偏移距离。
    • right: 相对于自身原位置的右侧的偏移距离。
  • 注意: 相对定位的设置有些反直觉,偏移距离可以分为正值和负值,但是和寻常的正值和负值不一样。
    • 正值:远离参照边缘的方向偏移(例如 left: 50px 表示元素左边缘相对于原始位置左边缘向右移 50px);
    • 负值:靠近参照边缘的方向偏移(例如 top: -20px 表示元素上边缘相对于原始位置上边缘向上移 20px)。

示例

可以看出相对定位的元素即使让开了位置,后面的元素也不会顶替它的位置,这些元素的排列不会受到影响,按照文档流的规则排列。

  • 示图:

    相对定位.jpg

  • 示例代码:

    .box {
        width: 200px;
        height: 60px;
        margin: 10px;
        line-height: 60px;
        text-align: center;
    }
    
    .relative-box {
        position: relative;
        left: 220px;
        /* 向原位置的右侧偏移220px */
        top: 20px;
        /* 向原位置的底部偏移20px */
        background: #ffcccc;
    }
    
    .normal-box {
        background: #ccffcc;
    }
    
    <div class="box relative-box">相对定位元素</div>
    <div class="box normal-box">文档流元素</div>
    

3. absolute(绝对定位)

position: absolute使得元素完全脱离了文档流既不按照文档流的规则排序,也不会保留其原有位置

  • 定位参考系:最近的已定位祖先元素,已定位祖先元素是指该祖先元素的position值为relativeabsolutefixedsticky,如果祖先元素中一个已定位元素都没有,那么就会相对于根元素(<html>)定位。

  • 比喻: 绝对定位就像一个人排队途中突然退出,这个位置就拱手让人了,并且这个人会以队伍中的好友作为位置参照物,进行活动,如果没有好友,那么他就用队伍的第一个人作为位置参照物。

示例

可以看出绝对定位元素彻底脱离了文档流,其原位置被别的元素占据了。

  • 示图: 绝对定位.jpg

  • 示例代码:

    .parent {
        position: relative;
        /* 父元素设为已定位,成为子元素的参考系 */
        margin: 100px 0 0 50px;
        width: 500px;
        height: 150px;
        padding: 10px;
        background: #f0f0f0;
        border: 2px solid #999;
    }
    
    .child {
        position: absolute;
        top: 30px;
        /* 距离父元素顶部30px */
        right: 20px;
        /* 距离父元素右侧20px */
        width: 200px;
        height: 60px;
        line-height: 60px;
        text-align: center;
        background: #ffcccc;
    }
    
    .other {
        position: absolute;
        height: 100px;
        /* 距离父元素顶部10px */
        top: 10px;
        background: yellow;
    }
    .end {
        height: 50px;
        line-height: 50px;
        background: #ccffcc;
        margin-top: 10px;
    }
    
    <div class="parent">
        父元素(已定位,作为参考系)
        <div class="child">子元素(absolute定位)</div>
    </div>
    <div class="other">中间的绝对定位元素</div>
    <div class="end">补位元素(会填补前方绝对定位元素的原位置)</div>
    

常见误解

相对于<body>定位而不是<html>

有的人会说:无已定位祖先元素的绝对定位元素,应该相对于<body>标签定位。这是一个错误的概念哦。因为所有 HTML 元素(包括 <body>)的初始定位状态都是 position: static,这是 CSS 规范明确规定的。没有理由要选择<body>作为定位参考系。

  • 示例: 从下图中可以清楚地看出,在所有祖先元素都没有定位时,绝对定位元素明显以根元素<html>标签作为参考系进行定位。
    • 示图:

      验证绝对定位参考系.jpg

    • 示例代码:

      /* 给html和body添加明显样式,方便观察 */
      html {
          background: #eee;
          /* 灰色背景 */
          padding: 20px;
          /* html有内边距 */
      }
      
      body {
          background: white;
          /* 白色背景 */
          margin: 30px;
          /* body有外边距 */
          padding: 30px;
          /* body有内边距 */
      }
      
      /* 绝对定位的元素:无任何定位祖先 */
      .box {
          position: absolute;
          top: 0;
          left: 0;
          width: 100px;
          height: 100px;
          background: red;
      }
      
      <div class="box">绝对定位的盒子</div>
      
认为绝对定位还是朝某方向偏移
  • 绝对定位与相对定位的不同之处:
    • 仔细想想,上面说的绝对定位的参考系是祖先元素啊!这意味着绝对定位元素是被包含在祖先元素的内部

    • 并且绝对定位是彻底脱离了文档流其原始位置也不会保留,你要朝某方向偏移,那么请问你从哪里开始偏移呢?原位置早就没了,你无法以它为参照点来偏移。

    • 所以这和相对定位的情况不一样。朝某方向偏移的说法对于绝对定位来说,是行不通的,应该是相对于参照容器边缘的距离,以其距离重新定位

      参照容器.jpg

  • 关键属性: 这里的topbottomleftright表示的就是绝对定位元素相对于参照容器边缘的距离
    • top: 相对于参照容器的顶部的距离。
    • bottom: 相对于参照容器的底部的距离。
    • left: 相对于参照容器的左侧的距离。
    • right: 相对于参照容器的右侧的距离。
  • 注意: 若同时设置 left 和 right,水平方向会拉伸元素(需宽度未固定);同理 top 和 bottom 会拉伸垂直方向(需高度未固定)。

4. fixed(固定定位)

position: fixed同样使得元素彻底脱离文档流,并且原有位置也不会保留。

  • 定位参考系: 始终相对于 浏览器视口(屏幕可见区域) 定位,滚动页面时位置不变;并且不受父元素布局影响(即使父元素有定位,仍以视口为参考)。
    • 最常见的就是掘金文章页面左侧的点赞(疯狂暗示)、评论、收藏、转发一栏了。

      掘金视口定位示例.jpg

    • 另外还需要强调,它的元素定位方式和绝对定位一样,都是 “根据距离重新定位”,而不是“朝某方向偏移”

      固定定位.jpg

  • 比喻: 排队时,这人被管理人员拉出来罚站,原位置被后面的人顶上去了,并且不管队伍怎么变化,都和他没关系了。

示例

从图中可以看出,不管怎么滑动,固定定位元素都在视口的固定位置。

  • 示图:

    固定定位.gif

  • 示例代码:

    .fixed-button {
        position: fixed;
        top: 30px;
        left: 300px;
        background-color: #4CAF50;
        color: white;
        padding: 15px;
        border-radius: 50%;
        cursor: pointer;
    }
    
    <div style="height: 2000px; padding: 20px;">
        <h1>页面内容</h1>
        <p>滚动页面查看固定按钮效果...</p>
    </div>
    
    <div class="fixed-button">返回顶部</div>
    

5. sticky(粘性定位)

position: sticky 可以说是 "相对定位" 和 "固定定位" 的混合体,分为两个阶段:

  • 阶段:
    • 滚动页面时,元素先按文档流排列(像relative);

    • 当滚动到预设阈值(通过top/bottom等设置),会固定在该位置(像fixed)。

    • 常见示例: 掘金文章页右上角的导航栏就是如此,在滚动一定位置后,固定在视口的右上角部分。

      掘金粘性定位示例.gif

  • 定位参考系: 通过topbottomleftright定义一个阈值,超过阈值时切换定位参考系,固定在视口对应位置。
    • 第一阶段(滚动未到达阈值前): 参照自身在文档流中的原始位置(类似 relative);
    • 第二阶段(滚动超过阈值后): 参照视口(类似 fixed)。

示例

可以看出经历了两个阶段,第一阶段的标题正常滚动,第二阶段的标题固定在视口区域的固定位置。

  • 示图: 粘性定位.gif

  • 示例代码:

    .sticky-title {
        position: sticky;
        top: 0;
        /* 阈值:当元素上边缘距离视口上边缘 ≤0 时,触发固定 */
        padding: 10px;
        background: lightgreen;
        /* 避免被其他元素覆盖 */
        z-index: 10;
    }
    
    .content1 {
        height: 300px;
    }
    .contentOther {
        height: 800px;
    }
    
    <div class="content1">内容1...</div>
    <h2 class="sticky-title">粘性标题(滚动试试)</h2>
    <div class="contentOther">内容2...</div>
    <div class="contentOther">内容3...</div>
    

补充:z-index

在粘性定位的示例代码中,大家有没有注意到这一行代码: z-index: 10;,它使得粘性定位的元素不会被其他元素覆盖。当多个元素在页面中重叠时(比如定位元素脱离文档流后覆盖其他元素),z-index 属性用于控制它们在 垂直于屏幕的方向(z 轴)  上的显示顺序 —— 值越大,元素越靠上(类似图层叠加)。你可以把z-index理解为优先级,优先级越高的,优先显示

  • 核心规则:
    • 只对 "定位元素" 生效:仅当元素的 position 为 relativeabsolutefixedsticky 时,z-index 才有效(position: static 元素设置 z-index 无效)。
    • 默认值为 auto:此时元素的堆叠顺序由其在 DOM 中的位置决定(后出现的元素默认在上方)。
    • 取值为整数:可正可负(如 z-index: 10z-index: -5),值越大,元素在 z 轴上越靠上。
    • 受 "堆叠上下文" 影响:每个元素属于一个 "堆叠上下文",子元素的 z-index 仅在父元素的堆叠上下文中生效(无法超越父元素的层级)。

示例1: 同一堆叠上下文中的元素重叠。

处于同一堆叠上下文时,就以元素的z-index的值为优先显示顺序的依据。

  • 示图:

    z-index示例1.jpg

  • 示例代码:

    .container {
                position: relative;
                /* 父容器,作为共同的堆叠上下文 */
                width: 500px;
                height: 500px;
                margin: 50px;
            }
    
    .box {
        position: absolute;
        /* 定位元素,支持z-index */
        width: 100px;
        height: 100px;
    }
    
    .box1 {
        top: 20px;
        left: 20px;
        background: red;
        z-index: 1;
        /* 层级1 */
    }
    
    .box2 {
        top: 50px;
        left: 50px;
        background: green;
        z-index: 2;
        /* 层级2(比box1高,显示在上方) */
    }
    
    .box3 {
        top: 5px;
        left: 110px;
        background: yellow;
        z-index: 0;
        /* 层级0(比box1低,显示在下方) */
    }
    
    <div class="container">
        <div class="box box1">box1(z=1)</div>
        <div class="box box2">box2(z=2)</div>
        <div class="box box3">box3(z=0)</div>
    </div>
    

示例2: 不同堆叠上下文的元素,子元素无法超越父元素层级。

很明显能看出子元素2的盒子模型覆盖了子元素1。

  • 示图:

    z-index示例2-1.jpg

    z-index示例2-2.jpg

  • 示例代码:

    .parent1 {
        position: relative;
        z-index: 1;
        /* 父1的层级为1 */
        width: 150px;
        height: 150px;
        background: rgba(255, 0, 0, 0.5);
        /* 半透明红色 */
    }
    
    .parent2 {
        position: relative;
        z-index: 2;
        /* 父2的层级为2(比父1高) */
        width: 150px;
        height: 150px;
        margin-top: -50px;
        /* 向上移动,与父1重叠 */
        background: rgba(0, 255, 0, 0.5);
        /* 半透明绿色 */
    }
    
    .child1 {
        position: absolute;
        z-index: 100;
        /* 子1的层级很高,但受限于父1 */
        width: 100px;
        height: 120px;
        background: red;
    }
    
    .child2 {
        position: absolute;
        z-index: 1;
        /* 子2的层级低,但父2层级高 */
        width: 100px;
        height: 100px;
        background: green;
    }
    
    <div class="parent1">
        <div class="child1">子元素1(z=100)</div>
    </div>
    <div class="parent2">
        <div class="child2">子元素2(z=1)</div>
    </div>
    
  • 讲解:

    • 父元素 parent2 的 z-index: 2 大于 parent1 的 z-index: 1,因此 parent2 整体在 parent1 上方;
    • 尽管 child1 的 z-index: 100 远大于 child2 的 z-index: 1,但 child1 属于 parent1 的堆叠上下文,child2 属于 parent2 的堆叠上下文,最终 child2 仍在 child1 上方(因父元素层级更高)。

定位小结

定位值是否脱离文档流定位参考系核心行为特点z-index 作用
static无(遵循文档流)top/left 等属性无效,默认布局无效(元素不参与堆叠,遵循文档流自然层级)
relative自身原位置偏移后保留原位置,不影响其他元素布局有效(可控制与其他定位元素的堆叠顺序)
absolute最近的已定位祖先(无则为根元素)脱离文档流,原位置被填补,依赖参考系定位有效(核心用于解决重叠时的显示层级,优先级高于未设置 z-index 的元素)
fixed浏览器视口完全固定,滚动时位置不变有效(常用于固定导航栏等,需控制与其他元素的堆叠关系)
sticky滚动到阈值后脱离视口先随文档流移动,达标后固定有效(固定时需处理与滚动元素的堆叠顺序)

三、版本弃子:浮动(Float)

浮动最初是为了解决 "文字环绕图片" 的问题(类似报纸排版),但后来被广泛用于布局。它的核心是让元素 "脱离文档流,但仍影响周围元素"。它也有几个关键属性,分别对应几种浮动情况:不浮动、左浮动、右浮动。

  • 特性:
    • 脱离文档流:浮动元素会从文档流中 "抽离",原有位置不再保留(后面的非浮动元素会向前填补);
    • 影响周围元素:不同于绝对定位(完全不影响其他元素),浮动元素会让后面的行内元素 / 文本环绕它;
    • 收缩包裹:浮动元素的宽度会默认 "收缩" 为内容宽度(类似inline-block)。

(一)浮动种类

1. none(默认,不浮动)

float: none就像定位的static一样,是元素关于浮动的默认值,此时元素仍处于文档流,遵循文档流的排序规则。

  • 示例
    • 示图:

      不浮动示例.jpg

    • 示例代码:

      .container {
          width: 300px;
          height: 300px;
          margin: 0 auto;
          border: 1px solid black;
      }
      .float-img {
          float: none;
          /* 图片不浮动(默认) */
          margin-right: 10px;
          /* 与文字保持距离 */
          height: 120px;
      }
      
      <div class="container">
          <img src="./img/哈基米.JPG" class="float-img">
          <p>《哈基米之歌》</p>
          <p>哈基米 哈基米 哈基米 哈基米
          哈基米 哈基米 我那咩鲁拖
          啊西嘎 啊西嘎 啊西嘎 啊西嘎
          啊西嘎 哈呀库 那录
          哈基米 哈基米 哈基米 哈基米
          哈基米 哈基米 我那咩鲁拖
          啊西嘎 啊西嘎 哈呀库 那录</p>
      </div>
      

2. left(左浮动)

float: left使得元素向左浮动,文字会自动环绕在元素右侧,多余的内容会自动换行,填补到元素下方。

  • 示例:
    • 示图:

      左浮动示例.jpg

    • 示例代码: 代码沿用不浮动情况的示例代码,只需修改.float-img样式

      .float-img {
          float: left;
          /* 图片向左浮动 */
          margin-right: 10px;
          /* 与文字保持距离 */
          height: 120px;
      }
      

3. right(右浮动)

float: right使得元素向右浮动,文字会自动环绕在元素左侧,多余的内容会自动换行,填补到元素下方。

  • 示例:
    • 示图:

      右浮动示例.jpg

    • 示例代码: 代码沿用不浮动情况的示例代码,只需修改.float-img样式

      .float-img {
          float: right;
          /* 图片向右浮动 */
          margin-right: 10px;
          /* 与文字保持距离 */
          height: 120px;
      }
      

(二)浮动被弃用的原因(父元素高度塌陷)

父元素的所有子元素都浮动,并且父元素没有规定高度(高度都得靠子元素撑开) 时,父元素会因为找不到内容支撑,造成一种我愿称之为 “皆若空游无所依” 的情况,使得父元素的高度为 0(即 "高度坍塌"),这是浮动最常见的问题。也有高度不为0时的塌陷情况

示例1 高度为0塌陷

示例中的父元素既没有规定高度,也没有用以支撑的子元素,使得出现高度塌陷,如果不是设置了边框宽度,我们都无法观察到父元素是否存在。

  • 示图: 高度塌陷示图.jpg

  • 示例代码:

    .parent {
        border: 2px solid red;
        /* 父元素边框 */
        width: 800px;
        /* 规定父元素宽度 */
    }
    
    .child {
        width: 200px;
        height: 200px;
        background: pink;
    }
    
    .float-left {
        float: left;
    }
    
    .float-right {
        float: right;
    }
    
    <!-- 现在子元素一个左浮动,一个右浮动,父元素完全没有内容支撑 -->
    <div class="parent">
        <div class="child float-left">
            子元素1
        </div>
        <div class="child float-right">
            子元素2
        </div>
    </div>
    

示例2 高度不为0的塌陷

塌陷情况不都是高度为0,也有出现高度较高的子元素浮动之后,只剩高度较小的子元素在父元素内,此时父元素仍会塌陷一部分,父元素高度转而让高度较小的子元素撑开。

  • 示图:

    • 未塌陷时

      高度未塌陷示图.jpg

    • 塌陷后

      高度不为0的塌陷.jpg

  • 示例代码:

    .parent {
        border: 2px solid red;
        /* 父元素边框 */
        width: 800px;
        /* 规定父元素宽度 */
    }
    
    .float-right {
        float: right;
        width: 300px;
        height: 500px;
        background: pink;
    }
    
    .no-float-child {
        width: 300px;
        height: 300px;
        background: pink;
    }
    
    <!-- 现在只留下了一个高度较低的子元素支撑 -->
    <div class="parent">
        <div class="child float-right">
            子元素1
        </div>
        <div class="no-float-child">
            子元素2
        </div>
    </div>
    

(三)补救:清除浮动

浮动有父元素高度塌陷这个致命缺陷,所以很多大佬开发了很多方法来清除浮动,这就是我们要学习的补救方法(不是简单地删除掉浮动元素的float属性!!!)。

清除浮动的本质

请记住,清除浮动的本质是:在保留浮动带来的布局价值的同时,修复它对父元素高度的破坏。不然我们直接把浮动元素的float属性注释掉不就行了,何必学这些清除浮动的方法呢。

  • 删除float属性的弊端: 删除float会失去浮动特有的布局效果(比如文字环绕、横向排列等),而我们的需求往往是 “既要这些效果,又要解决高度坍塌”

方法一(BFC):父元素加 overflow: hidden

overflow: hidden 会触发父元素的 BFC(块级格式化上下文)。BFC 有个特性:会自动包裹住内部的浮动元素,就像给父元素加了一个 “隐形的框”,把浮动子元素框在里面。这样就给了父元素一个高度支撑,不会造成塌陷。

  • 示例代码: 父元素高度恢复,粉色背景和红色边框能完整包裹住浮动的蓝色子元素,后续元素也不会乱跑了。
    .parent {
        overflow: hidden;
        /* 关键代码 */
        background: pink;
        border: 2px solid red;
    }
    
    .child {
        float: left;
        width: 100px;
        height: 100px;
        background: blue;
    }
    

方法二:在浮动元素后加一个 clear: both 的空元素

clear: both 的意思是 “不允许当前元素的左右两侧有浮动元素”。这个空元素不浮动,会在文档流中占据位置,迫使父元素 “撑开” 高度,从而包裹住前面的浮动子元素。这个相当于在爆胎的汽车下面放了个千斤顶,并且这个千斤顶的高度为左右两个轮子的高度取最高,完美支撑了父元素。

  • 示例代码: 父元素会被这个空元素 “撑高”,高度刚好能包含浮动子元素,背景和边框正常显示。

    .float {
        float: left;
        width: 100px;
        height: 100px;
        background: blue;
    }
    
    .clear {
        clear: both;
    }
    
    /* 关键代码:清除左右浮动的影响 */
    .parent {
        background: pink;
        border: 2px solid red;
    }
    
    <div class="parent">
      <div class="child float">浮动子元素</div>
      <!-- 新增一个空元素,专门清除浮动 -->
      <div class="clear"></div>
    </div>
    

方法三:伪元素清除法(最推荐)

用父元素的 ::after 伪元素模拟一个 “空元素”(和方法 2 的逻辑一样),这个伪元素在所有子元素的最后,通过 clear: both 迫使父元素包裹住浮动子元素。

  • 优势: 不用在 HTML 里加额外的空元素(不污染代码),效果和方法 2 一样,并且不会像方法一一样隐藏超出父元素范围的内容,是目前最常用的方式。

  • 示例代码:

    .parent::after {
        content: "";
        /* 必须有content,否则伪元素不显示 */
        display: block;
        /* 转为块级元素,才能占位置 */
        clear: both;
        /* 清除浮动 */
    }
    
    .parent {
        background: pink;
        border: 2px solid red;
    }
    
    .child {
        float: left;
        width: 100px;
        height: 100px;
        background: blue;
    }
    

四、总结

文档流、定位和浮动并非孤立存在,它们共同构成了 CSS 布局的基础逻辑:

  • 文档流是 "默认规则":元素按顺序排列,是布局的起点;
  • 定位是 "打破规则":通过absolute/fixed完全脱离文档流,实现精准定位;通过relative/sticky在文档流中微调或动态固定;
  • 浮动是 "灵活调整":脱离文档流但保留对文本的影响,适合环绕布局或简单横向排列(需注意清除浮动)。

结语

在实际开发中,现代布局更推荐使用 Flexbox 或 Grid,但理解这三者的原理,能帮你解决各种 "奇奇怪怪" 的布局问题(比如旧项目维护、特殊交互场景)。记住:布局的核心是 "控制元素在页面中的位置关系",而文档流、定位和浮动,正是控制这种关系的底层逻辑。
希望这篇文章能帮你彻底搞懂这三个概念,让 CSS 布局从此变得清晰起来!如果本篇文章有错误或者缺漏,请在评论区指出,我们共同进步,谢谢🙏。