理解css2.1中的float

理解float

什么是float

float布局可以让一个box移动到某一行的左边或者右边的边缘,float box附近的line boxes会环绕在float box周围。

当一个box向左向右浮动,直到自己的margin edge碰触到containing block的边缘或者其它float boxmargin edge为止。如果box是从一个line box里面float出来的,则这个float boxtop margin edge会与line box的顶部边缘对齐。

如果一个float box在水平方向的浮动空间不够,则这个box就会向下移动直到有足够的浮动空间给它。

float会导致box脱离文档流,会造成高度塌陷的问题。在float box之后的line boxes,如果在垂直方向上的位置关系与float box发生重叠,则会自动缩减宽度以便为float boxmargin box留出足够的空间,形成环绕效果。如果line box在垂直方向的位置与float box不重叠,则line box不会缩减宽度。

看这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<!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 type="text/css">
.parent {
line-height: 30px;
color: #fff;
background-color: #ccc;
width: 500px;
min-height: 300px;
margin: 0 auto;
}

.child {
width: 100px;
height: 100px;
background-color: orange;
margin: 10px;
float: left;
}

.line1 {
background-color: red;
}

.line2 {
background-color: blue;
}

.line3 {
background-color: green;
}

.line4 {
background-color: sienna;
}

.line0 {
background-color:skyblue;
}

.line5 {
background-color: slateblue;
}
</style>
</head>

<body>
<div class="parent">
<div class="line0">0</div>
<div class="child"></div>
<div class="line1">1</div>
<div class="line2">2</div>
<div class="line3">3</div>
<div class="line4">4</div>
<div class="line5">5</div>
</div>
</body>
</html>

上面只有1、2、3、4的内的line box与floateddiv.child在垂直位置上发生了重叠,所以它们的宽度自动缩减了,而0、5则没有。

如果一个line box宽度缩减后太短了,以至于没法容纳任何的内容,则这个line box会向下移动直到它的内容能够显示得下或者不再与float发生重叠,之后宽度会自动恢复。比如这个例子:

1
2
p { width: 10em; border: solid aqua; }
span { float: left; width: 5em; height: 5em; border: solid blue; }

1
2
3
4
<p>
<span> </span>
Supercalifragilisticexpialidocious
</p>

spanfloat box,理论上后面文本应该环绕它,但是这个文本是个连续单词不会自动折断,导致它对应的inline box在变窄后的line box里展示不下,所以line box自动移动到了float box下面展示。 当它到了下面的时候,其实宽度也是不够的,但是这个不是float导致的,此时line box旁边已经没有float box了,所以line box不会再向下移动,最后只能溢出了。

同一个BFC中的,使用未脱离文档流的方式创建了新BFCbox、以及table、或blocl-level的替换元素,它们的border box,不允许与它所在的BFC中的任何float boxmargin box发生重叠!如有必要,浏览器可以对这些BFC box设置浮动清除以便让它们显示在 float box的下面,但是如果空间足够的话,也可以将它们放置在float box的旁边,甚至可以去缩减这些boxborder box的宽度。 但是css2.1并没有定义浏览器什么时候可以把BFC box放置在float box旁边以及这些BFC box可以缩减多少。 这个要点其实就能解释为什么新建BFC可以用来实现两栏分栏布局。比如这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!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 type="text/css">
.contaienr {
color: #fff;
background-color: #ccc;
width: 500px;
min-height: 300px;
margin: 0 auto;
}

.aside {
float: left;
width: 100px;
min-height: 100px;
background-color: slateblue;
}

.main {
/* BFC */
display: table-cell;
width: 2000px;
min-height: 100px;
background-color: brown;
}
</style>
</head>

<body>
<div class="contaienr">
<div class="aside">coldplay</div>
<div class="main">something just like this</div>
</div>
</body>

</html>

float box会有堆叠效果,看起来就像float box创建了新的堆叠上下文一样,不同之处在于其它定位元素以及会创建新的堆叠上下文的元素都会参与到float boxparent stacking context当中。 这里介绍的堆叠上下文与格式化上下一样,是一个布局概念,跟z-index层级有关系。一开始的那句话,是一个类比,实际上float并没有创建堆叠上下文,但是float与文档流中的内容会产生堆叠效果。float box可以与文档流中的其它box发生重叠,float boxblock-levelbox重叠是很容易的,那它如何与inline-box重叠呢?line box不是会环绕float吗?有1种情况是可以让inline-boxfloat发生重叠的,就是利用负的margin值。 当float与文档流中的内容发生重叠后,叠放顺序为:float会渲染在非定位的block box之上,在inline box的内容之下。强调一定是非定位的block box,因为定位的block box会产生堆叠上下文,而此处讨论的堆叠效果,跟堆叠上下文没有关系。看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!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 type="text/css">
.contaienr {
width: 500px;
padding: 10px;
border: 1px solid #ccc;
}

.p {
margin: 1em;
padding: 10px;
border: 5px solid #ccc;
}

.p span {
width: 100px;
height: 200px;
float: left;
background-color: skyblue;
margin: 10px;
}

.p div {
margin-left: -57px;
background: red;
color: #fff;
display: inline-block;
}
</style>
</head>

<body>
<div class="contaienr">
<div class="p">Lorem ipsum dolor sit amet consectetur adipisicing elit. Qui vero quae nostrum debitis
<span></span>necessitatibus commodi, soluta ea amet perferendis magni voluptate provident nam. Dicta ducimus
rerum aspernatur id eaque assumenda.</div>
<div class="p">
<div>Lorem ipsum dolor</div> sit amet consectetur adipisicing elit. Qui vero quae nostrum debitis
necessitatibus commodi, soluta ea amet perferendis magni voluptate provident nam. Dicta ducimus rerum
aspernatur id eaque assumenda.
</div>
</div>
</body>

</html>

从效果图很清晰的看到,float与文档流中的内容发生了重叠,float box很明显地盖住了div的边框,说明float box渲染在block-leveldiv元素之上;然后有一个内层div,被变为了inline block box,并设置了负的margin值,导致它最后渲染在了float box之上。

floatproperty

float这个属性用来定义浮动方式,定义如下:

Value: left | right | none | inherit
初始值: none
应用于: 基本上所有元素
是否可被继承: 否
百分比计算: 不支持

  • left 代表向左浮动
  • right 代表向右浮动
  • none 表示不浮动

left为例,来说明浮动的一些规则:

  • 如果一个boxfloat: left,并且在它之前还有left-floatingboxes,那么当前这个box与前一个float box的关系,要么是当前这个boxleft margin edge紧贴着前一个float boxright margin edge,要么是当前这个boxtop margin edge低于前一个float boxbottom margin edge
    看这个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    <!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 type="text/css">
    .contaienr {
    width: 500px;
    height: 200px;
    border: 1px solid #ccc;
    color: #fff;
    font-size: 20px;
    margin: 0 auto;
    }

    div.a {
    float: left;
    width: 200px;
    height: 150px;
    background-color: slateblue;
    }

    div.b {
    float: left;
    width: 200px;
    height: 80px;
    background-color: steelblue;
    }

    div.c {
    float: left;
    width: 200px;
    height: 50px;
    background-color: violet;
    }
    </style>
    </head>

    <body>
    <div class="contaienr">
    <div class="a">A</div>
    <div class="b">B</div>
    <div class="c">C</div>
    </div>
    </body>

    </html>

    下图是效果,图中B C都贴在A的右边,C贴在B的下面:

浮动相关规则:

  1. The left outer edge of a left-floating box may not be to the left of the left edge of its containing block. An analogous rule holds for right-floating elements.
  2. If the current box is left-floating, and there are any left-floating boxes generated by elements earlier in the source document, then for each such earlier box, either the left outer edge of the current box must be to the right of the right outer edge of the earlier box, or its top must be lower than the bottom of the earlier box. Analogous rules hold for right-floating boxes.
  3. The right outer edge of a left-floating box may not be to the right of the left outer edge of any right-floating box that is next to it. Analogous rules hold for right-floating elements.
  4. A floating box’s outer top may not be higher than the top of its containing block. When the float occurs between two collapsing margins, the float is positioned as if it had an otherwise empty anonymous block parent taking part in the flow. The position of such a parent is defined by the rules in the section on margin collapsing.
  5. The outer top of a floating box may not be higher than the outer top of any block or floated box generated by an element earlier in the source document.
  6. The outer top of an element’s floating box may not be higher than the top of any line-box containing a box generated by an element earlier in the source document.
  7. A left-floating box that has another left-floating box to its left may not have its right outer edge to the right of its containing block’s right edge. (Loosely: a left float may not stick out at the right edge, unless it is already as far to the left as possible.) An analogous rule holds for right-floating elements.
  8. A floating box must be placed as high as possible.
  9. A left-floating box must be put as far to the left as possible, a right-floating box as far to the right as possible. A higher position is preferred over one that is further to the left/right.

clearproperty

clear这个属性用来清除浮动,定义如下:

Value: none | left | right | both | inherit
初始值: none
应用于: block-level元素
是否可被继承: 否
百分比计算: 不支持

浮动清除的作用是为了让元素的左右不出现float box,只对相同BFC中的float box有效,同时对自己内部的float box无效。

各个值的含义如下:

  • left 要求boxtop border edge必须低于任何在它之前生成的left-floating boxbottom margin edge
  • right 要求boxtop border edge必须低于任何在它之前生成的left-floating boxbottom margin edge
  • both 要求bottop border edge必须低于任何在它之前生成的left-floating boxright-floating boxbottom margin edge
  • none 不清除浮动

none值的clear属性,会在需要的时候,增加clearance(间隙),clearance会阻碍外边距合并,在盒子模型里面学margin合并的条件时了解过;clearance这段空白的空间是加在被clearboxtop margin edge之上的,以便能在垂直方向上把box推到float box的底下去。clearance是看不到的。

clearance效果:

clearance这段空白空间大小如何计算出来呢?css官方文档里面有算法,浏览器替我们实现了。

float box也可以设置清除浮动,规则是:

  • 设置了clear: leftfloat boxtop margin edge必须低于它之前的任何left-floating boxbottom margin edge
  • 设置了clear: rightfloat boxtop margin edge必须低于它之前的任何right-floating boxbottom margin edge
  • 设置了clear: bothfloat boxtop margin edge必须低于它之前的任何left-floating boxright-floating boxbottom margin edge