正常文档流和脱离文档流

正常文档流

文档流:元素在页面中出现的先后顺序。正常文档流:普通(文档)流,将页面从上到下分成一行一行的,其中块元素独占一行,相邻行内元素在每一行中按照从左到右排列,直到该行排满的布局情况,即默认情况下页面元素的布局情况。

  1. <body>
  2. <div></div>
  3. <span></span><span></span>
  4. <p></p>
  5. <span></span><i></i>
  6. <img />
  7. <hr />
  8. </body>

image.png

脱离文档流

脱离正常文档流,使用浮动或是定位。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title></title>
    <style type="text/css">
        /*定义父元素样式*/
        #father {
            width: 500px;
            background-color: #0C6A9D;
            border: 1px solid silver;
        }

        /*定义子元素样式*/
        #father div {
            padding: 20px;
            margin: 15px;
            border: 2px dashed red;
            background-color: #FCD568;
            text-align: center;
        }
    </style>
</head>

<body>
    <div id="father">
        <div id="son1">box1</div>
        <div id="son2">box2</div>
        <div id="son3">box3</div>
    </div>
</body>

</html>

上面定义了 3 个 div 元素。对于这个 HTML 来说,正常文档流,指的就是从上到下依次显示这 3 个 div 元素。由于 div 是块元素,因此每个 div 元素独占一行。

设置浮动

#son3,#son2
{
  float: left;
}

image.png 在正常文档流的情况下,div 是块元素,会独占一行。但是由于设置了浮动,第 2 个、第 3 个 div 元素并列一行,并且跑到父元素之外,跟正常文档流不一样。也就是说,设置浮动使得元素脱离了正常文档流。

设置定位

#son3
{
  position: absolute;
  left: 400px;
  top: 50px;
}

image.png
由于设置了定位,第 3 个 div 元素就跑到父元素的上面去了。也就是说,设置了定位使得元素 脱离了正常文档流。

深入浮动

正常文档流情况下,块元素都是一行一行的,如果把多个块元素并排到一行,可以使用浮动将块元素脱离正常文档流来实现。

浮动使得元素移动到左边或者右边,并且允许后边的文字或元素环绕它,常用于实现水平方向上的并排布局,而不是垂直方向的布局。

两个重要特点

首先,当元素定义为 float 之后,不管之前是什么类型,都会变成 block 类型, 也就是说,浮动元素会表现为块元素效果,然后可以定义 width、height、padding 和 margin。使用 margin-left/right 来定义浮动元素与其他元素之间的间距。

其次,当一个元素定义了 float 时,这个元素就会脱离文档流,后面元素会紧跟着填上空缺的位置。

浮动的影响

对自身的影响

元素设置为 float 之后成为块元素,可以设置宽高,padding,margin。

对父元素的影响

已知元素设置浮动之后就会脱离正常文档流,如果浮动元素的 height 大于父元素的高度 height,或者父元素没有定义高度,此时父元素不能把子元素包起来,浮动元素就会脱离父元素,这就是所谓的“父元素高度塌陷”。

对兄弟元素的影响

兄弟元素是浮动元素

这里要注意两点,首先是兄弟元素的浮动效果,另外就是父元素的宽高。

同一方向的兄弟元素

当一个浮动元素碰到同一个方向的兄弟元素时,这些元素会从左到右,从上到下,一个接一个紧挨着排列。排列方式与父元素的宽高有关。

相反方向的兄弟元素

两个元素移向两边。

兄弟元素不是浮动元素

<!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 type="text/css">
      div {
        width: 600px;
        height: 300px;
        border: 1px solid black;
        background-color: antiquewhite;
        float: left;
        margin: 50px;
      }

      span
      {
        float: none;
        width: 200px;
        height: 200px;
        border: 1px solid black;
        margin: 10px;
        text-align: center;
        background-color: aquamarine;
      }

      #d1 {
        float: left;
      }
      #d2
      {
        float: right;
      }
    </style>
  </head>

  <body>
    <div>
      <div id="d3">div no-float</div>
      <span id="d1">span float-left</span>
      <div id="d3">div no-float</div>
    </div>
    <div>
      <span id="d1">span float-left</span>
      <div id="d3">div no-float</div>
      <span id="d1">span float-left</span>
    </div>
    <div>
      <span id="d1">span float-left</span>
      <div id="d3">div no-float</div>
      <div id="d3">div no-float</div>
    </div>
    <div>
      <span id="d1">span float-left</span>
      <span id="d1">span float-left</span>
      <div id="d3">div no-float</div>
    </div>

  </body>

</html>

image.png
浮动元素对原来的元素有着覆盖效果,可见其对布局的影响非常大,因此在实际开发时,使用了浮动之后要注意清除浮动。

对子元素的影响

当父元素没有定义 height,浮动元素会脱离父元 素,造成父元素高度塌陷。但是当父元素同时也是一个浮动元素的时候,这个父元素会自适应地包含该子元素。

浮动布局的副作用

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title></title>
    <style type="text/css">
        #father {
            width: 300px;
            overflow: hidden; 隐藏溢出
            border: 1px solid black;
            background-color: lightskyblue;
        }

        #first,
        #second {
            width: 100px;
            height: 50px;
            border: 1px solid red;
        }

        #first {
            float: left;
        }

        #second {
            float: right;
        }
    </style>
</head>

<body>
    <div id="father">
        <div id="first"></div>
        <div id="second"></div>
    </div>
</body>

</html>

这里为父元素添加 overflow:hidden 清除浮动,使边框能够撑开。由上文可知,另一种方式是在父元素添加 flow:left,不过最终效果不同。

用法解释:https://www.jianshu.com/p/d07048762efa

清除浮动

清除浮动,其实就是清除元素被定义浮动之后带来的脱离文档流的影响。我们知道,浮动可以使元素移到左边或者右边,然后后面的文字或元素会环绕着这个浮动元素。如果我们不想浮动元素后面的元素环绕着它,希望后面的元素回归到正常文档流中去,这个时候我们可以清除浮动。

clear:both

在 CSS 中,我们可以使用 clear 属性来清除浮动。clear 属性取值有 3 种:left、right 和 both。一般情况下使用 clear:both 来清除所有浮动。clear 属性不是应用于浮动元素本身,而是应用于浮动元素后面的元素。

<!DOCTYPE html> 
<html>
  <head>
    <meta charset="utf-8" />
    <title></title>
    <style type="text/css">
      #father
      {
        width:300px;
        border: 1px solid black;
      }
      #first,#second
      {
        width:100px;
        height:50px;
        border:1px solid red;
      }
      #first{float:left;}
      #second{float:right;}
      /*关键代码,清除浮动*/
      .clear{clear:both;}
    </style>
  </head>
  <body>
    <div id="father">
      <div id="first"></div>
      <div id="second"></div>
      <div class="clear"></div>
    </div>
  </body>
</html>
使用 clear:both 来清除浮动,往往会多添加一个 div 标签。这个 div 标签仅仅是为了清除浮动而添加的,没有任何其他意义。这种方法并不太好,因为它会增加多余的标签,还会破坏 HTML 代码的语义。如果页面要清除多次浮动,就会无缘无故添加很多多余的 div 标签。    

overflow:hidden

<!DOCTYPE html> 
<html>
  <head>
    <meta charset="utf-8" />
    <title></title>
    <style type="text/css">
      #father
      {
        overflow:hidden;       /*关键代码,清除浮动*/
        width:300px;
        border:1px solid black;
      }
      #first,#second
      {
        width:100px;
        height:50px;
        border:1px solid red;
      }
      #first{float:left;}
      #second{float:right;}
    </style>
  </head>
  <body>
    <div id="father">
      <div id="first"></div>
      <div id="second"></div>
    </div>
  </body>
</html>

注意 overflow:hidden 应用于浮动元素的父元素,而不是当前的浮动元素。

::after 元素

.clearfix{*zoom:1;}
.clearfix::after
{
  clear:both;
  content:"";
  display:block;
  height:0;
  visibility:hidden;
}

对于使用 ::after 伪元素结合 clear:both 来清除浮动,推荐把这个样式定义成一个公共的 class,这个 class 一般取名为“.clearfix”然后对这个类进行全局引用,这样可以减少重复的 CSS 代码。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title></title>
    <style type="text/css">

        .clearfix::after {
            clear: both;
            content: "";
            display: block;
            height: 0;
            visibility: hidden;
        }

        #father {
            width: 300px;
            border: 1px solid black;
        }

        #first,
        #second {
            width: 80px;
            height: 40px;
            border: 1px solid red;
        }

        #first {
            float: left;
        }

        #second {
            float: right;
        }
    </style>
</head>

<body>
    <div id="father" class="clearfix">
        <div id="first"></div>
        <div id="second"></div>
    </div>
</body>

</html>
使用 clear:both 清除浮动会增加多余的标签,使用 overflow:hidden 清除浮动会使超出父元素的部分被隐藏。使用 ::after 伪元素来清除浮动,则不会有这些缺点。