10.4 浮动定位方案

浮动float严格讲属于定位方案,同时它广泛的运用于列式布局,也称作float布局。

列式布局目前主要有两种方案:float列式布局、flex列式布局。flex列式布局提供各种强大功能,约10个CSS属性。浮动布局功能简单,只有1个属性。float的优点:简单、不支持弹性。很多网站的PC端前台仍使用float布局,一方面考虑兼容问题,另一方面因为页面需要精准尺寸不允许弹性。

术语说明。float元素指float: left或right的元素。


10.4.1 float特点经典场景

float特点经典场景包括两个场景。

场景1:跨多个行盒line box。float元素跨一个IFC内多个line box,常见于图文环绕。

img

示例代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小步教程</title>

    <style>
        .div1{
            background-color: #ed7d31;
        }
        .div1::first-line{
            background-color: #0aaa76;
            padding-left: 20px;
        }
    </style>
</head>
<body>
    <div class="div1">
        <img src="image/logo.jpg" style="float: left;margin-right: 10px;">
        小步教程 xiaobuteach.com 很长的一段文字描述,
        很长的一段文字描述很长的一段文字描述很长的一段文字描述,
        很长的一段文字描述很长的一段文字描述很长的一段文字描述,
        很长的一段文字描述很长的一段文字描述很长的一段文字描述。
    </div>
</body>

</html>

float表示左浮。伪元素::first-line选择第1个行盒line box。

运行效果

img

场景2:跨多个div。float元素在垂直方向跨多个div。

img

代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小步教程</title>
    <style>
        .parent{
            background-color: #0aaa76;
        }

        .float{
            float:left ;
            height: 100px;
            background-color: #4aa6fc;
        }

        .div2{
            background-color: #ed7d31;
        }
    </style>
</head>
<body>
    <div class="parent">
        <div class="float">浮动内容</div>
        <div class="div1">
            <span>div1 小步教程 xiaobuteach.com</span>
            <span>小步教程 xiaobuteach.com</span>
            <span>小步教程 xiaobuteach.com</span>
        </div>
            
    </div>
    <div class="div2">div2</div>
</body>
</html>

父元素包含float元素,float元素高度是100px。父元素包含非浮动内容,又包含浮动内容;下方还有一个块。

运行效果

img

说明父元素parent高度height: auto计算具体值时,不会参考float元素的高度,会参考其它正常流定位元素的高度,所以导致下一个div也显示在float元素的右边。


10.4.2 float盒子特点

特点1:float盒子具有占位。float元素同一行的行盒line box的宽度相应变小,下方行盒识别到float元素高度而排列在下方。所以float元素与正常流定位元素不会重叠。

特点2:float盒子高度不参与父盒高度计算。上述两个示例证明父元素具备识别内部float元素的宽度与高度的能力,特意设计成不采纳它的高度。这个设计保证float元素能跨多个行盒与跨多个div。

特点3:所属BFC的创建元素能识别浮动元素高度,查看各元素的offsetHeight验证。查看parent、body、html三个盒子的offset高度。

img

根元素html的offsetHeight包含了float元素的高度。

特点4:float盒子半脱离流。从两个角度理解float盒子是否脱离流:(1)从完全自动计算坐标的角度,属于脱离流定位;(2)从占位角度,存在占位,影响后续元素位置。综合所述,float通常称为脱离流或半脱离流。


10.4.3 父盒识别float盒子高度

父盒识别float盒子高度主要包括两种方法。

(1)新建BFC识别高度。可通过display: flow-root或overflow: hidden等方式实现。

<div class="parent" style="display: flow-root;">

(2)clear方法清除浮动。父元素内部结束添加clear:both的子元素,或通过伪类实现。

        .parent::after{
            content:'';
            display:block;
            clear:both;
        }

运行效果说明父元素识别其高度,计算样式面板查看parent高度进一步验证。

img


10.4.4 float经典错误场景

float特点经典场景2页面效果

img

这是实际项目经常出现的经典错误场景,换成如下页面内容可能更熟悉。

img

“菜单项2”这个float元素的高度超出父元素的高度,占据下方div第1个行盒的相应位置,导致内容右移。

问题代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小步教程</title>

    <style>
        .parent{
            background-color: #0aaa76;
            height: 20px;
        }

        .float{
            float:left ;
            height: 20px;
            background-color: #4aa6fc;
        }

        .div2{
            background-color: #ed7d31;
        }

        .parent::after{
            content:'';
            display:block;
            clear:both;
        }
    </style>
</head>
<body>
    <div class="parent">
        <div class="float">菜单项1</div>    
        <div class="float" style="height: 23px;">菜单项2</div>    
        <div class="float">菜单项3</div>    
        
    </div>
    <div class="div2">主体内容 小步教程 xiaobuteach.com</div>
</body>
</html>

parent高度20px,“菜单项2”高度23px超出,即使21px也出现同样问题。

多种解决方法:(1)调整float元素高度小于等于父div高度,(2)溢出内容进行隐藏。如果是不小心设置过高则需用第1种方法。


10.4.5 float列式布局与浮动塌陷

前面研究了float元素的本质,接下来讲解float用于列式布局。

float布局实现一行多列包括两个步骤:各列设置浮动;clear属性清除浮动。

(1)单行场景

例1:一行三列。先不清浮除动。

<body>
    <div>
        <div style="float: left;width: 100px;">
            <div>第1行第1列</div>
            <div>小步教程</div>
        </div>
        <div style="float: left;width: 150px;">
            <div>第1行第2列</div>
            <div>xiaobuteach.com</div>
        </div>
        <div style="float: left;width: 150px;">
            <div>第1行第3列</div>
            <div>每列可嵌套复杂布局</div>
        </div>   
    </div>
</body>

运行效果正常

img

(2)下一行上移现象

例2:共3行,第1行分3列。

<body>
    <div>
        <div style="float: left;width: 100px;">第1行第1列</div>
        <div style="float: left;width: 100px;">第1行第2列</div>
        <div style="float: left;width: 100px;">第1行第3列</div>   
    </div>

    <div>第2行</div>

    <div>第3行 小步教程 xiaobuteach.com</div>
</body>

运行结果不正常。

img

第2行没有换行,第3行正常换行,这就是浮动塌陷。


(3)浮动塌陷

开发者工具查看第1行的div的实际高度等于0。

img

浮动塌陷:父div如果没有设置高度则根据内部内容自动计算;当子div设置float属性为left或right,父div计算高度时不会参考它的高度;当一个父div的所有子元素全是float,父元素的高度则为0。当父div后续还有div则会导到上移现象。


10.4.6 解决浮动塌陷的四种方法

方法1:设置clear:both来清除浮动。在最后一个float列之后添加clear:both的div。

    <div>
        <div style="float: left;width: 100px;">第1行第1列</div>
        <div style="float: left;width: 100px;">第1行第2列</div>
        <div style="float: left;width: 100px;">第1行第3列</div>
        <div style="clear: both;"></div>
    </div>

清除浮动的div的位置与其它列元素并列。运行效果如下。

img

开发者工具查看父div高度正常。


方法2:伪元素清除浮动。伪元素::after实现添加上一步的专用div,本质同方法1。

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>CSS 伪类清除浮动 | 小步教程</title>

    <style>
        .clearfix::after {
            content: '';
            display: block;
            clear: both;
        }
    </style>
</head>

<body>
    <div class="clearfix">
        <div style="float: left;width: 100px;">1行1列</div>
        <div style="float: left;width: 100px;">1行2列</div>
        <div style="float: left;width: 100px;">1行3列</div>
    </div>

    <div>第2行</div>
    <div>第3行 小步教程 xiaobuteach.com</div>
</body>

</html>

实际项目会把clearfix类放在公用CSS文件。


方法3:BFC方案。设置overflow:flow-root创建新的BFC,方法本质是:所属BFC的创建元素能识别浮动元素高度。

<body>
    <div style="overflow: flow-root;">
        <div style="float: left;width: 100px;">1行1列</div>
        <div style="float: left;width: 100px;">1行2列</div>
        <div style="float: left;width: 100px;">1行3列</div>   
    </div>

    <div>第2行</div>
    <div>第3行 小步教程 xiaobuteach.com</div>
</body>

运行效果正常。


方法4:设置塌陷元素的高度。当浮动元素高度较小,父div手动设置较大高度,也会正常显示。如果父元素没有手动设置高度,而内部还存在其它的普通子元素(非float),且普通子元素高度大于float元素高度,也能正常显示。


10.4.7 float自动换行

父div包含多列float元素,如果一行排列不下则自动换行。

示例代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小步教程</title>
</head>
<body>
    <div style="width: 450px;border: 1px solid #666;display: flow-root;">
        <div style="float: left;width: 100px;background-color: #0aaa76;">
            <div>第1行第1列</div>
            <div>小步教程</div>
        </div>
        <div style="float: left;width: 150px;background-color: #4aa6fc;">
            <div>第1行第2列</div>
            <div>xiaobuteach.com</div>
        </div>
        <div style="float: left;width: 150px;background-color: #ed7d31;">
            <div>第1行第3列</div>
            <div>每列可嵌套复杂布局</div>
        </div>   
    </div>
</body>

</html>

父div内容宽度450px,3列总宽度400px,则在一行显示。

img

调整第3列宽度为200px,则刚好完全占满一行。

img

调整第3列宽度为201px,一行放不下则整列自动换行。

img

float元素自动换行的三种场景。

场景1:正常应用场景。典型场景是商品列表分多行显示,无需直接指定行数,会根据内部float元素个数及相关宽度而自动换行产生相应行数。

场景2:错误场景。部分场景不需要换行,因为尺寸设计错误导致float列宽之和超出父div宽度,此时自动换行成为错误,需相应调整float元素列宽与父div宽度。

场景3:溢出内容进行显示。部分特殊场景允许float列宽之和超出父div宽度,但不允许换行,超出内容也称溢出内容,需要对溢出内容进行显示。float本身不支持不自动换行,可改成flex布局,或者间接实现。间接实现思路:float父div设计足够容纳float各列的宽度,float爷div设计目标宽度,父div默认会在爷div溢出显示,因为overflow默认值visible表示针对溢出进行显示。

示例代码如下

<body>
    <div style="width: 400px;border: 1px solid #666;">
        <div style="border: 1px solid #c00;display: flow-root;width: 500px;">
            <div style="float: left;width: 100px;background-color: #0aaa76;">
                <div>第1行第1列</div>
                <div>小步教程</div>
            </div>
            <div style="float: left;width: 150px;background-color: #4aa6fc;">
                <div>第1行第2列</div>
                <div>xiaobuteach.com</div>
            </div>
            <div style="float: left;width: 200px;background-color: #ed7d31;">
                <div>第1行第3列</div>
                <div>每列可嵌套复杂布局</div>
            </div>
        </div>
    </div>
</body>

运行效果

img


10.4.8 float右对齐

<div>元素a</div>
<div>元素b</div>

假设上述两个元素设置成右对齐float: right,浏览器渲染过程按代码顺序渲染,首先将元素a放在最右,然后将元素b放在该行剩块空间的最右,所以最终效果先b再a。如果想按a、b顺序显示在右,可以使用如下结构,在外层div设置一个float: right即可。

<div>
    <div>元素a</div>
    <div>元素b</div>
</div>