CSS - 布局 - 浮动

729 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

float 属性可以指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它

float 属性最初只用于在一段文本内浮动图像, 实现文字环绕的效果,也就是实现图文环绕效果

但是早期的CSS标准中并没有提供好的左右布局方案, 因此在一段时间里面它成为网页多列布局的最常用工具

但如今出现flex布局和grid布局后,已经很少再去使用浮动进行布局和定位

绝对定位、浮动都会让元素脱离标准流,以达到灵活布局的效果

可以通过float属性让元素产生浮动效果

说明
none不浮动,默认值
left向左浮动
right向右浮动

浮动规则

  1. 元素一旦浮动后, 脱离标准流

    • 朝着向左或向右方向移动,直到自己的边界紧贴着包含块(一般是父元素)或者其他浮动元素的边界为止
    • 如果元素是向左(右)浮动,浮动元素的左(右)边界不能超出包含块的左(右)边界
    • 定位元素会层叠在浮动元素上面

    LjGlch.png

    L9g6JD.png

<!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>Document</title>
    <style>
      .box {
        width: 300px;
        height: 300px;
        background-color: red;
        padding: 30px;
      }

      .left,
      .right {
        background-color: blue;
        color: #fff;
      }

      .left {
        float: left;
      }

      .right {
        float: right;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <span class="left">left</span>
      <span class="right">right</span>
    </div>
  </body>
</html>
  1. 浮动元素之间不能层叠
    • 如果一个元素浮动,另一个浮动元素已经在那个位置了,后浮动的元素将紧贴着前一个浮动元素
    • 如果水平方向剩余的空间不够显示浮动元素,浮动元素将向下移动,直到有充足的空间为止
  2. 浮动元素不能与行内级内容层叠,行内级内容将会被浮动元素推出
    • 这里指代的行内级元素除了行内级元素、inline-block元素,还包括块级元素的文字内容
    • 我们可以利用这个特性来实现图文环绕效果

浮动前: L9glnX.png

浮动后: LjG6wS.png

<!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>Document</title>
  <style>
    .container {
      width: 300px;
      background-color: gray;
      display: flow-root;
    }

    .box {
      width: 150px;
      height: 150px;
      color: #000;
    }

    .box1 {
      background-color: red;
      float: left;
    }

    .box2 {
      background-color: #0f0;
    }

    span {
      color: skyblue;
    }
  </style>
</head>
<body>
  <!--
    div.container的高度由内容撑开
    可以看到div.box1向左浮动 div.box2上移 的时候
    文本2依旧在原位,且不占据空间
  -->
  <div class="container">
    <div class="box box1">1</div>
    <!--
      因为div.box1向左浮动了
      所以div.box2自动上移,被div.box1覆盖
      但是因为浮动元素不能覆盖行内级元素
      所以文本2还是在原位,不会上移
    -->
    <div class="box box2">2</div>
  </div>
  <span>Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptate, ad.</span>
</body>
</html>
<!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>Document</title>
  <style>
    .box {
      width: 300px;
      border: 1px solid red;
      background-color: rgba(0, 0, 0, 0.3);
    }

    img {
      width: 150px;
      float: left;
    }
  </style>
</head>
<body>
  <div class="box">
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Vel, numquam?
    Temporibus a soluta velit? Eos voluptatem earum quos assumenda vitae.
    <img src="./images/favicon.ico">
    Labore fugit explicabo minus consequuntur nobis repellat earum consequatur eveniet?
    Nulla, ipsum esse vel omnis ab ducimus illo labore nostrum.
  </div>
</body>
</html>
  1. 行内级元素、inline-block元素浮动后,其顶部将与所在行的顶部对齐
    • 也就是说浮动只能进行左浮动和右浮动
    • 无法实现上浮动和下浮动
    • 对于位于同一行的多个浮动元素而言,他们之间的对齐方式是顶部对齐

LjGVxW.png

应用场景

去除元素间间隙

我们可以使用浮动来解决行内级元素、inline-block元素的水平间隙问题

LjGAl2.png

<!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>Document</title>
    <style>
      .box {
        width: 100px;
        height: 100px;
        display: inline-block;
      }

      .box1 {
        background-color: #f00;
      }

      .box2 {
        background-color: #0f0;
      }

      .box3 {
        background-color: #00f;
      }
    </style>
  </head>
  <body>
    <!-- 
			为了增加代码的可读性
			我们会在元素之间添加空格并进行换行
			但是浏览器解析的时候,会默认将换行解析为空格
			所以这就导致了元素和元素之间默认会产生一定的间隙
		-->
    <div class="box box1"></div>
    <div class="box box2"></div>
    <div class="box box3"></div>
  </body>
</html>
解决方法说明备注
去除空格和换行不利于代码的可维护性和可读性不推荐
将父元素的font-size设置为0font-size是个继承属性
这就意味着在子元素中,需要将font-size的值进行重置
否则所有元素的font-size皆会为0,页面什么都不显示
不推荐
将元素按照相同的方向进行浮动浮动元素之间没有间隙,且各个浮动元素之间不会覆盖
为元素开启定位通过调整元素的定位来移除元素间的空格
使用margin的负值通过margin的负值
设置父元素的display为flex开启BFC推荐

浮动结合margin负值模拟nth-child的效果

<!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>Document</title>
  <style>
    .container {
      width: 1190px;
      background-color: rgba(0, 0, 0, 0.5);
      display: inline-block;
    }

    .wrap {
      /* 
      	因为对于border-box而言
      	fatherWidth = marginLeft + marginRight + width
      	1190 = -5 + -5 + auto
      	此时子元素的宽度就成为了 1200px
      	也就是通过将margin的值设置为负值
        将width拉伸为1200px 
      	从而模拟:nth-of-child(5n)的效果
      */
      margin: 0 -5px;
    }

    .box {
      width: 230px;
      height: 322px;
      line-height: 322px;
      text-align: center;
      font-size: 25px;
      background-color: #00f;
      color: #fff;
      /*
      	因为元素设置了 margin: 0 -5px;
      	必然导致div.box的位置向左偏移了5px
      	所以需要在子元素调整回来
      */
      margin: 0 5px 10px;
      float: left;
    }
  </style>
</head>
<body>
  <div class="container">
    <!-- 
			额外嵌套一层以便于通过设置margin的负值来拉伸容器 
		-->
    <div class="wrap">
      <div class="box box1">1</div>
      <div class="box box2">2</div>
      <div class="box box3">3</div>
      <div class="box box4">4</div>
      <div class="box box5">5</div>
      <div class="box box6">6</div>
      <div class="box box7">7</div>
      <div class="box box8">8</div>
    </div>
  </div>
</body>
</html>

基本案例

LjRTqL.png

<!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>Document</title>
  <style>
    .container {
      display: flow-root;
      width: 1190px;
      background-color: #333;
      margin: 0 auto;
    }

    .wrap {
      margin-right: -10px;
    }

    .box {
      width: 290px;
      height: 180px;
      line-height: 180px;
      text-align: center;
      margin-right: 10px;
      margin-bottom: 10px;
      background-color: red;
      float: left;
      font-size: 26px;
      color: #fff;
    }

    .item {
      height: 370px;
    }
  </style>
</head>
<body>
  <div class="container">
    <!-- 
			在内容和容器盒子之间多包裹一层div
			以便于设置负的margin来对整体进行布局
		-->
    <div class="wrap">
      <div class="box item">1</div>
      <div class="box item">2</div>
      <div class="box">3</div>
      <div class="box">4</div>
      <div class="box">5</div>
      <div class="box">6</div>
      <div class="box">7</div>
      <div class="box">8</div>
      <div class="box">9</div>
      <div class="box">10</div>
    </div>
  </div>
</body>
</html>

清除浮动

浮动元素由于脱离了标准流,变成了脱标元素,所以不再向父元素汇报高度

所以父元素计算总高度时,就不会计算浮动子元素的高度,导致了高度坍塌的问题

解决父元素高度坍塌问题的过程,一般叫做清浮动(清理浮动、清除浮动)

也就是让父元素计算总高度的时候,把浮动子元素的高度算进去

clear

我们清除浮动最常见的方式是使用clear属性

clear 属性可以指定一个元素是否必须移动(清除浮动后)到在它之前的浮动元素下面

说明
none默认值,无特殊要求
left要求元素的顶部低于之前生成的所有左浮动元素的底部 --- 清除左浮动
right要求元素的顶部低于之前生成的所有右浮动元素的底部 --- 清除右浮动
both要求元素的顶部低于之前生成的所有浮动元素的底部 --- 清除左浮动和右浮动
<!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>Document</title>

  <style>
    .box {
      width: 600px;
      background-color: red;
      color: #fff;
    }

    .content {
      width: 300px;
      background-color: blue;
      float: left;
    }

    .line {
      clear: both;
    }
  </style>
</head>
  <div class="box">
    <div class="content">
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus, omnis.
      Consequuntur dolorum laboriosam incidunt rem deleniti neque autem ad odio?
      Neque iusto velit porro ut qui quis, ex doloremque tenetur.
    </div>
    <!--
      添加空元素 目的是为了清除浮动
      div.line元素必须在浮动元素的下边
      相对于起到一个占位符的作用
      这样父元素div.box就可以知道浮动元素的高度
      此时父元素的高度就会撑开,后边的元素也就不会自动上移
    -->
    <div class="line"></div>
  </div>
<body>
</body>
</html>

但是使用html元素清除浮动的时候,我们需要在页面中创建很多的空的html元素用于清除浮动

这必然会增加很多无意义的空标签,维护麻烦,所以我们可以使用伪元素来实现相同的功能

<!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>Document</title>

  <style>
    .box {
      width: 600px;
      background-color: red;
      color: #fff;
    }

    .content {
      width: 300px;
      background-color: blue;
      float: left;
    }

    .clear-fix::after {
      content: '';
      clear: both;
      /*
        默认伪元素是行内级非替换元素
        默认的宽度为内容的宽高
      	所以默认是0px * 0px 并无法起到占位清除浮动的作用
      	所以需要设置display: block; 
      	或 display: inline-block; + width: 100%;
      */
      display: block;

      /*
        兼容老版本 --- 现代浏览器可以不用
        在一些老版本浏览器里面
        伪元素如果不设置对应的内容的时候
        会有默认的内容存在
        所以需要隐藏元素, 并将高度置为零
      */
      visibility: hidden;
      height: 0;
    }
  </style>
</head>
  <div class="box clear-fix">
    <div class="content">
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus, omnis.
      Consequuntur dolorum laboriosam incidunt rem deleniti neque autem ad odio?
      Neque iusto velit porro ut qui quis, ex doloremque tenetur.
    </div>
  </div>
<body>
</body>
</html>