# CSS浮动float详解

返回:一般常见样式处理及开发技巧

TIP

浮动就是一个变态,魔鬼,自私自利且影响他人的混球。
浮动出现的意义其实只是用来让文字环绕图片而已,仅此而已。

# 特性一:包裹性

返回顶部

所谓包裹性一目了然。block元素不指定width的话,默认是100%,一旦让该div浮动起来,立刻会像inline元素一样产生包裹性,宽度会跟随内容自适应。(这也是通常float元素需要手动指定width的原因)

2020-10-26_171855.jpg

.noAbsoluteDiv {
  border: 3px solid #1890ff;
}

.withFloat {
  border: 3px solid yellowgreen;
  float: left;
}
1
2
3
4
5
6
7
8
<div className={ styles.noAbsoluteDiv }><img alt="rmb22" src={ rmb52 } height={ 63 }/></div>
<div style={ { height: 15 } }>&nbsp;</div>
<div className={ styles.withFloat }><img alt="rmb22" src={ rmb22 } height={ 63 }/></div>
1
2
3

再加上一个div的话

<div className={ styles.noAbsoluteDiv }><img alt="rmb22" src={ rmb52 } height={ 63 }/></div>
<div style={ { height: 15 } }>&nbsp;</div>
<div className={ styles.withFloat }><img alt="rmb22" src={ rmb22 } height={ 63 }/></div>
<div style={{ border: '3px solid aqua' }}><img alt="rmb22" src={ rmb12 } height={ 63 }/></div>
1
2
3
4

2020-10-26_172111.jpg

效果非常近似于display:inline-block。但相比之下,浮动能设定为左浮和右浮,但display:inline-block都是从左到右排列的。
(还有些细微差别,两个display:inline-block间会有空隙,但两个float间没有。这不是本篇的主题,暂时略过)

# 特性二:高度欺骗

返回顶部

例1中浮动float被设在了外围div上,因此高度欺骗性没体现出来。现在给内层img元素设定float。

<div className={ styles.noAbsoluteDiv }>
    <img alt="rmb22" src={ rmb52 } height={ 63 }/>
</div>
<div style={ { height: 15 } }>&nbsp;</div>
<div style={ { border: '3px solid yellowgreen' } }>
    <img style={ { float: 'left' } } alt="rmb22" src={ rmb22 } height={ 63 }/>
</div>
1
2
3
4
5
6
7

2020-10-26_172550.jpg

TIP

内容img由于加上了float,使得该img具有了欺骗性。float给img施了个障眼法,让该img的inline-height高度塌陷为0了。这样外层div计算高度时,认为img的高度为0,相当于div的content的高度为0,因此绿色边框看起来是一条直线。

但请注意障眼法毕竟是障眼法,并不是真的让img的高度塌陷为0了,可以看到上图中img的黄色边框还是有正常高度的。如果给div里加点文字,效果如下

2020-10-26_172814.jpg

WARNING

可以看到,外层div在没有手动设定height的前提下,其高度是由内部content的最大高度决定的,
由于img的float使得img具有高度塌陷的欺骗性,让div误以为img的line-height为0,因此div的高度就是文字的匿名inline-box的inline-height。

因此浮动并不是让元素的高度塌陷了,而是让元素具有高度塌陷的欺骗性。骗谁?骗别人!但骗不了自己,元素自身还是有高度的

回过头再看看浮动float的本意:让文字像流水一样环绕图片。重要的事情多看几遍...给div设定一个width:200px,并加点文字吧:

<div style={ { border: '3px solid yellowgreen', width: 180 } }>
    <img style={ { float: 'left' } } alt="rmb22" src={ rmb22 } height={ 63 }/>
    我还有个文字我还有个文字我还有个文字我还有个文字我还有个文字我还有个文字我还有个文字我还有个文字
</div>
1
2
3
4

2020-10-26_173713.jpg

# 这就是浮动元素的本意

<ul style={{ width: 512 }}>
    <li style={ { width: 138, margin: '0 10px', textAlign: 'center', float: 'left' } }>
        <div><img src={ rmb11 } alt="" height={ 63 }/>尼古拉斯.旺财</div>
    </li>
    <li style={ { width: 138, margin: '0 10px', textAlign: 'center', float: 'left' } }>
        <div><img src={ rmb21 } alt="" height={ 63 }/>功夫熊猫</div>
    </li>
    <li style={ { width: 138, margin: '0 10px', textAlign: 'center', float: 'left' } }>
        <div><img src={ rmb12 } alt="" height={ 63 }/>月野兔</div>
    </li>
    <li style={ { width: 138, margin: '0 10px', textAlign: 'center', float: 'left' } }>
        <div><img src={ rmb22 } alt="" height={ 63 }/>猫女郎</div>
    </li>
</ul>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

2020-10-26_174454.jpg

如果好友再长点呢?

2020-10-26_174541.jpg

姓名最大高度的好友来决定每行的高度。

TIP

将浮动float改成 display:inline-block 就行了

代码只需将上面float:left;替换成display: inline-block;,没对齐只需给li加上个vertical-align: top;
(上面提到过,相比float,display:inline-block中间会有空隙,眼神好的可以从图中就能看出来,解决方案不是本篇的主题,可以问度娘)。这下高度自适应了,每行的高度都是以名字最长的高度为准。

<ul style={ { width: 512 } }>
    <li style={ {
        width: 138,
        margin: '0 10px',
        textAlign: 'center',
        display: 'inline-block',
        verticalAlign: 'top'
    } }>
        <div><img src={ rmb11 } alt="" height={ 63 }/>尼古拉斯.旺财.julia roberts</div>
    </li>
    <li style={ {
        width: 138,
        margin: '0 10px',
        textAlign: 'center',
        display: 'inline-block',
        verticalAlign: 'top'
    } }>
        <div><img src={ rmb21 } alt="" height={ 63 }/>功夫熊猫</div>
    </li>
    <li style={ {
        width: 138,
        margin: '0 10px',
        textAlign: 'center',
        display: 'inline-block',
        verticalAlign: 'top'
    } }>
        <div><img src={ rmb12 } alt="" height={ 63 }/>月野兔</div>
    </li>
    <li style={ {
        width: 138,
        margin: '0 10px',
        textAlign: 'center',
        display: 'inline-block',
        verticalAlign: 'top'
    } }>
        <div><img src={ rmb22 } alt="" height={ 63 }/>猫女郎</div>
    </li>
</ul>
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

2020-10-26_175037.jpg

TIP

回过头看用float来水平布局。是好是坏呢?好处是上手简单,随便什么程度的CSSer都能搞定。坏处是有时需要定高难以自适应。
而display:inline-block;属性可是根正苗红的水平布局的属性,可以用其替代float。让float尽量多的干其本职工作:让文字像流水一般环绕浮动元素

# 清除浮动

返回顶部

先明确一个概念,用clear确实能达到我们期望的清除浮动的效果,这点没异议。但深入点看,究竟是清除了什么样的浮动呢?

<div style={ { border: '4px solid blue' } }>
<div style={ { width: 200, border: '4px solid red', float: 'left' } }>
    我是浮动元素_red
</div>
<div style={ { width: 200, border: '4px solid yellow', float: 'left' } }>
    我是浮动元素_yellow
</div>
<div style={{clear:'both'}}></div>
</div>
<div style={ { border: '4px solid gray', clear: 'left' } }>我是页脚</div>
1
2
3
4
5
6
7
8
9
10

2020-10-26_175724.jpg

但是:我们脑海真真正期望的清除浮动后的样子难道不是下面这样吗?让清除浮动后,原本被欺骗的外层div获得正确的高度!

# 闭合浮动

闭合浮动的实现方法很多

  • 常见的是最后增加一个清除浮动的子元素:
<div style={ { border: '4px solid blue' } }>
    <div style={ { width: 200, border: '4px solid red', float: 'left' } }>
        我是浮动元素_red
    </div>
    <div style={ { width: 200, border: '4px solid yellow', float: 'left' } }>
        我是浮动元素_yellow
    </div>
    <div style={{ clear: 'both' }} />
</div>
<div style={ { border: '4px solid gray', clear: 'left' } }>我是页脚</div>
1
2
3
4
5
6
7
8
9
10

2020-10-26_180015.jpg

缺点是会增加一个DOM节点。

  • 同样可以在最后增加一个清除浮动的br:将上面代码中<div style=”clear:both;”></div>替换成<br clear=”all” />即可。语义上比空的div标签稍微好一点,但同样会增加一个DOM节点。
  • 父元素设置 overflow:hidden(如果你还要兼顾IE6的话,加上*zoom:1;来触发hasLayout)

这看起来很奇怪。因为子元素的浮动的高度欺骗,导致父元素误认为content高度为0(即蓝色边框为一条线),所以父元素设成overflow:hidden溢出隐藏的话,直觉上应该子元素由于溢出导致不显示才对,即整个页面只显示页脚。但实际效果,父元素设成overflow:hidden溢出隐藏后,竟然神奇地出现了闭合浮动的效果(蓝色边框正确获得了高度)。这是怎么回事呢?靠的是BFC,

  • 同上面将父元素设置 的overflow:hidden改成auto
  • 父元素也设成float。
  • 父元素设置display:table。效果OK,页脚也不需要设clear:left,但父元素的盒子模型被改变了
  • 用:after伪元素,思路是用:after元素在div后面插入一个隐藏文本”.”,隐藏文本用clear来实现闭合浮动: