float 属性是 CSS 中常用的一个属性, 在实际工作中使用的非常多, 如果使用不当就会出现意料之外的效果. 虽然很多人说浮动会用就行, 浮动过时了, 但是对于优秀的前端开发人员, 需要有 "刨根问底" 的精神, 这样在出现一些问题的时候才不至于 "手慌脚乱"! 因此, 今天就特别整理和总结一下 float 属性.
1. float 介绍
CSS 世界中的 float 属性是一个年代非常久远的属性, 设置了 float 属性的元素会根据设置的属性值向左或者向右浮动, 直到它的外边缘碰到包含框或另一个浮动框的边框为止. 设置了 float 属性的元素会从普通文档流中脱离, 相当于不占据任何空间, 所以文档中普通流中的元素表现的就像浮动元素不存在一样, 因此, 设置 float 属性的后会影响我们的页面布局. 具体说来就是: 让 block 元素无视 float 元素, 让 inline 元素像流水一样围绕着 float 元素实现浮动布局.
float 属性设计的初衷:
仅仅是让文字像流水一样环绕浮动元素
, 就像下图中展示的一样:
2. float 的特性
float 有哪些有意思的特性呢? 具体如下:
包裹性
高度塌陷
块状化
没有任何 margin 合并
下面将详细阐述这几点的含义.
2.1 包裹性
所谓 "包裹性", 其实是由 "包裹" 和 "自适应" 两部分组成. 假设有以下 CSS 代码:
- /* CSS 代码 */
- .father{
- border: 1px solid deeppink;
- width: 200px;
- }
- .son {
- float: left;
- font-size: 0;
- border: 1px solid blue;
- padding: 5px;
- }
- .father img {
- width: 128px;
- }
1) 包裹. 本例中将浮动元素父元素宽度设置为 200px, 浮动元素的子元素是一个 128px 宽度的图片, 则此时浮动元素宽度表现为 "包裹", 也就是里面图片的宽度 128px.
- /* html 代码 */
- <div class="father">
- <div class="son">
- <img src="../../lib/img/mm1.png">
- </div>
- </div>
2) 自适应性. 在浮动子元素的中增加一些文字:
- /* HTML 代码 */
- <div class="father">
- <div class="son">
- <img src="../../lib/img/mm1.png">
- <span style="font-size: 12px"> 美女 1, 美女 2, 美女 3, 美女 4, 美女 5, 美女 6, 后宫 1, 后宫 2, 后宫 3, 后宫 </span>
- </div>
- </div>
此时, 浮动元素宽度就自适应父元素的 200px 宽度, 最终的宽度表现也是 200px. 如下图所示:
2.2 高度塌陷
float 属性有一个著名的特性: 会让父元素的高度塌陷. 如章节 2.1 中的效果图, 父元素 div 的高度并没有被子元素撑开 (粉色区域), 这种效果可以称为 "高度塌陷". 导致高度塌陷的原因是因为浮动元素脱离了正常的文档流, 则 div.father 认为其没有子元素, 所以产生了高度塌陷. 后文中将讲述如何解决高度塌陷的问题.
2.3 块状化
块状化的意思是, 一旦元素 float 的属性不为 none, 则其 display 计算值就是 block 或者 table. 举个例子:
- /* JavaScript 代码 */
- var span = document.createElement('span')
- document.body.appendChild(span)
- console.log('1.' + window.getComputedStyle(span).display)
- // 设置元素左浮动
- span.style.cssFloat = 'left'
- console.log('2.' + window.getComputedStyle(span).display)
在控制台中的结果如下:
1.inline 2.block
不知道大家有没有跟我一样的疑问: 既然设置 float 后, 元素就块状化了, 那么怎么还能产生包裹性的效果呢? 回答这个问题, 需要重新阐述下块状化的意思, 这里的块状化意思是可以像 block 元素一样设置宽和高, 并不是真正的块元素.
因此, 没有任何理由出现下面的样式组合:
- span{
- display: block; /* 多余 */
- float: left;
- }
- span{
- float: left;
- vertical-align: middle; /* 多余 */
- }
2.4 没有任何的 margin 重叠
在这里, 我们将. son 类增加 margin:10px 样式, 在浏览器中查看实际效果.
- /* HTML 代码 */
- <div class="father">
- <div class="son">
- <img src="../../lib/img/mm1.png">
- </div>
- <div class="son">
- <img src="../../lib/img/mm1.png">
- </div>
- <div class="son">
- <img src="../../lib/img/mm1.png">
- </div>
- </div>
我们增加. son 类的 margin 为 10px, 在浏览器中查看相邻的. son 元素的空白区域的高度是 20px, 可以发现设置了 float 属性的元素没有任何的 margin 重叠, 这和普通的元素 margin 重叠不一样.
3. float 与流体布局
使用 float 可以通过破坏正常的文档流实现 CSS 环绕, 但是却带来了 "高度塌陷" 的问题! 然而我们可以利用 float 破坏正常文档流的特性实现一些常用的布局:
文字环绕变身 - 中间内容居中, 左中右布局
直接看例子:
- <div class="box">
- <a href="javascript:;" class="fl"> 左青龙 </a>
- <a href="javascript:;" class="fr"> 右白虎 </a>
- <h3 class="text-center"> 标题 </h3>
- </div>
- .box{
- background-color: #f5f5f5;
- }
- .fl{
- float: left;
- }
- .fr{
- float: right;
- }
- .text-center{
- text-align: center;
- }
从下图中看出, 实现了中间内容居中的左中右布局.
文字环绕的衍生 - 单侧固定
- <div class="father">
- <img src="../../lib/img/008.JPG">
- <p class="girl"> 美女 1, 美女 2, 美女 3, 美女 4, 美女 5, 美女 6, 后宫 1, 后宫 2, 后宫 3, 后宫 4, 后宫 5, 后宫 6</p>
- </div>
- .father{
- border: 1px solid #444;
- overflow: hidden;
- }
- .father> img {
- width: 60px; height: 64px;
- float: left;
- }
- .girl {
- /* 环绕和自适应的区别所在 */
- margin-left: 70px;
- }
和文字环绕效果相比, 区别就是. girl 多了一个 margin-left: 70px, 同时图片的宽度设置 60px, 因此不会发生文字环绕的效果. 这里, 我们也可以不使用 margin-left, 改用 border-left 或者 padding-left 都可以达到改变 content box 的尺寸, 从而实现宽度自适应布局效果.
4. float 的克星
既然使用 float 属性会带来一系列的问题, 那么有没有办法消除这些问题呢? 答案是: 肯定有. 接着看下文.
4.1 clear 属性
在 CSS 中可以使用 clear 来清除 float 属性带来高度塌陷等问题, 使用格式如下:
clear: none | left | right | both
none: 默认值, 允许两边都有浮动对象;
left: 不允许左侧有浮动对象;
right: 不允许右侧有浮动对象;
both: 两侧不允许有浮动对象.
如果单从字面上的意思来理解, clear:left 应该是 "清除左浮动",clear:right 应该是 "清除右浮动", 实际上, 这种说法是有问题的, 因为浮动一直还在, 并没有清除! 只能清除浮动带来的影响.
官方对 clear 属性的解释是:"元素盒子的边不能和前面的浮动元素相邻". 注意这里的 "前面的"3 个字, 也就是 clear 属性对 "后面的" 浮动元素是不闻不问的. clear 属性只能清除元素的自身, 不能影响其他的元素. 接着看下面的这个例子:
- /* HTML 代码 */
- <div class="box1"></div>
- <div class="box2"></div>
- /* CSS 代码 */
- .box1 {
- float: left;
- width: 100px;
- height: 60px;
- padding: 10px;
- border: 3px solid black;
- background: url("../../lib/img/mm1.png") center no-repeat;
- }
- .box2 {
- border: 3px solid red;
- padding:10px;
- width:100px;
- height: 60px;
- background: url("../../lib/img/mm2.jpg") center no-repeat;
- }
如上图所示, box1 元素为设置了左浮动, 已经脱离了正常的文档流, 所以 box2 能够在 box1 的底层显示. 如果想让 box2 能够换行排列, 则只需要在. box2 类中增加 clear:left 样式即可. 如下图所示:
4.2 clear 属性的不足
clear 属性只对块级元素有效, 但是::after 等伪元素默认都是内联水平, 因此, 在实际工作中, 我们常常使用下面的代码来清除浮动带来的影响:
- .clear::after{
- content: "";
- display: table;/* 也可以是'block'或者是'list-item'*/
- clear: both;
- }
由于 clear:both 作用的本质是让自己不和 float 元素在一行显示, 并不是真正意义上的清除浮动, 因此 float 元素有一些不好的特性依然存在, 表现在:
如果 clear:both 元素前面的元素就是 float 元素, 则设置 margin-top 无效;
- /* HTML 代码 */
- <div class="box1"></div>
- <div class="box2"></div>
- /* CSS 代码 */
- .box1 {
- float: left;
- width: 100px;
- height: 60px;
- padding: 10px;
- border: 3px solid black;
- background: url("../../lib/img/mm1.png") center no-repeat;
- }
- .box2 {
- clear: both;
- margin-top: -20px;
- border: 3px solid red;
- padding:10px;
- width:100px;
- height: 60px;
- background: url("../../lib/img/mm2.jpg") center no-repeat;
- }
在本例中, 设置. box2 中的 margin-top 没有任何的效果, 如下图所示:
clear:both 后面的元素依旧可能会发生文字环绕现象.
- <div class="father">
- <div class="float">
- <img src="../../lib/img/mm1.png">
- </div>
<p> 美女 1, 美女 2, 美女 3, 美女 4, 美女 5, 美女 6, 后宫 1, 后宫 2, 后宫 3, 后宫 </p>
- </div>
- <div> 我要美女 1, 我还要美女 2</div>
- /* CSS 代码 */
- .father{
- border: 1px solid deeppink;
- width: 500px;
- height: 70px;
- }
- .father:after{
- content: '';
- display: table;
- clear: both;
- }
- .float{
- float: left;
- }
- .father img {
- width: 60px;
- height: 70px;
- }
在本例中, 设置 clean:both 来阻止浮动对后面元素的影响, 但是最后的错位效果依然发生了 (可以设置. father 的字体大小为 0, 然后设置 p 标签的字体大小解决错误的问题).
由此可见, clear:both 只能在一定程度上消除浮动的影响, 要想完美去除浮动元素的影响, 借助其他的手段 --BFC, 接着看下文.
5. CSS 世界的结界 --BFC
5.1 BFC 的定义
BFC 全称
block formatting context
, 中文为 "块级格式化上下文".BFC 的表现原则为: 如果一个元素具有 BFC, 那么它的内部子元素再怎么翻江倒海, 都不会影响外部的元素. 因此, BFC 元素是不可能发生 margin 重叠的, 另外, BFC 元素也可以用来清除浮动的影响.
那么满足什么条件才会有 BFC 呢? 只要满足下面任意一个条件就会触发 BFC:
html 根元素;
float 的值不为 none;
overflow 的值为 auto,scroll 或者 hidden;
display 的值为 table-cell,table-caption 和 inline-block 中的任何一个;
position 的值不为 relative 和 static;
触发 BFC 后, 就不需要使用 clear:both 属性去清除浮动的影响.
5.2 BFC 的作用
清除 margin 重叠
- /* HTML 代码 */
- <div class="parent">
- <p>item 1</p>
- <p>item 2</p>
- <p>item 3</p>
- <p>item 4</p>
- </div>
- /* CSS 代码 */
- .parent{
- width: 300px;
- background-color: black;
- overflow: hidden;
- }
- p {
- background-color: white;
- margin: 10px 0;
- text-align: center;
- }
在这种情况下, 出现了 margin 重叠的效果. 如下图所示:
利用 BFC 能消除 margin 重叠, 谨记: 只有当元素在同一个 BFC 中时, 垂直方向上的 margin 才会 clollpase. 如果它们属于不同的 BFC, 则不会有 margin 重叠. 因此我们可以再建立一个 BFC 去阻止 margin 重叠的发生. 所以为了让他们的 margin 变成 20px, 我们只需要用 div, 建立一个 BFC, 令 p 元素处于不同 BFC 即可. 请看例子:
- /* HTML 代码 */
- <div class="parent">
- <p>item 1</p>
- <p>item 2</p>
- <div style="overflow: hidden">
- <p>item 3</p>
- </div>
- <p>item 4</p>
- </div>
从下图中可以看出, 借助 BFC 消除了 margin 重叠的问题.
清除高度塌陷的问题
在上面的章节中, 如果子元素设置浮动属性, 则父元素就会出现高度塌陷的问题. 在这里, 我们可以借助 BFC 消除高度塌陷的问题了, 请看下面的这个例子:
- /* HTML 代码 */
- <div style="border: 1px solid deeppink;width: 200px; overflow: hidden">
- <img src="../../lib/img/mm1.png" style="border: 1px solid blue; float: left">
- </div>
从下图中可以看到, 设置 overflow:hidden 样式后就产生了 BFC, 根据 BFC 的表现规则, 内部元素的样式不会影响外部元素的样式, 因此没有出现高度塌陷的问题.
自适应布局 (阻止文本换行)
- /* HTML 代码 */
- <div class="parent">
- <img src="../../lib/img/mm1.png">
- <p class="girl"> 美女 1, 美女 2, 美女 3, 美女 4, 美女 5, 美女 6, 后宫 1, 后宫 2, 后宫 3, 后宫 4,</p>
- </div>
地方
- /* CSS 代码 */
- .parent{
- border: 1px solid deeppink;
- width: 200px;
- font-size: 0;
- }
- .parent img{
- border: 1px solid blue;
- float: left;
- }
- .girl{
- /*overflow: hidden;*/
- font-size: 12px;
- background-color: #cdcdcd;
- }
如果我们给. girl 元素设置具有 BFC 特性的属性, 如: overflow: hidden 就可以实现更健壮, 更智能的自适应布局.
这里的. girl 元素为了不和浮动元素产生任何交集, 顺着浮动边缘形成自己的封闭上下文.
普通元素在设置了 overflow:hidden 后, 会自动填满容器中除了浮动元素意外的剩余空间, 形成自适应效果, 这种自适应布局和纯流体布局相比:
自适应内容由于封闭而更加健壮, 容错性更强;
自适应内容能够填满除浮动元素以外区域, 不需要关心浮动元素宽度.
6. 结语
本文是我学习 float 属性总结文章, 可能存在理解准确的地方, 欢迎大家在评论区评论, 指点迷津, 大家互相帮助, 互相进步.
来源: https://segmentfault.com/a/1190000014554601