c52c403ab33a98c86fe95fcd9616bb1a.png

原创:itsOli  @前端一万小时

本文版权归作者所有,未经授权,请勿转载!

本文节选自“语雀”私有付费专栏「前端一万小时 | 从零基础到轻松就业」

bcb21a1708af23ed1460ae35e4e19562.png

1. 浮动元素有什么特征?对父容器、其他浮动元素、普通元素、文字分别有什么影响?
2. 清除浮动指什么?如何清除浮动?两种以上方法。

?上方面试题“参考答案详解”,请点击文末“


前言:前 10 篇文章,我们基本上都是在用“理论”学习“理论”。从这篇开始,我们试着用“实践”来学习理论,然后又用于实践。

一个原则:把代码拷贝到 JS Bin 上,对照效果搞懂每行代码“是什么”、“为什么”、“怎么样”?

1 为什么需要“浮动”

假设我们需要有个东西,然后它的排版不是依照盒模型的定义——从上往下依次排列,而是从左到右这种结构,那么我们需要考虑到使用“浮动”。

例如一个网站的头部,一部分在左边,一部分在右边。首先,“部分”的表示我们会用 div,而 div 是块级元素,按理说它会从上到下,占据一整行,不可能整列排列。那这个时候我们就需要“浮动”。

2 “浮动”是怎么用的,有什么表现效果

2.1 放不下会换行

一个“浮动盒”会向左或向右移动,直到其外边(outer edge)挨到包含块边沿或者另一个浮动盒的外边。如果没有足够的水平空间来浮动,它会向下移动,直到空间合适或者不会再出现其他浮动了。

?源码及效果展示 https://jsbin.com/xixikovapi/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>前端一万小时title>
head>
<body>
  <div class="ct">
    <div class="box box1">①div>
    <div class="box box2">②div>
    <div class="box box3">③div>
  div>
body>
html>
CSS

.ct {width: 280px;height: 300px;margin: 100px;border: 1px solid black;
}.box {float: left; /* ?直接在你需要浮动的元素上加 float 属性。 */width: 100px;height: 100px;background: red;color: #fff;
}.box1 {background: blue;
}.box2 {background: pink;
}

db5cf05da1666050a8bed5ca5ffb3aa0.png

?对比:
?源码及效果展示 https://jsbin.com/fesesoreyo/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bintitle>
head>
<body>
  <div class="ct">
    <div class="box box1">①div>
    <div class="box box2">②div>
    <div class="box box3">③div>
  div>
body>
html>
CSS

.ct {width: 280px;height: 300px;margin: 100px;border: 1px solid;
}.box {float: right;width: 100px;height: 100px;background: red;color: #fff;
}/* ?站在浏览器的角度看,它会挨着顺序依次渲染。 */.box1 {background: blue;
}.box2 {background: pink;
}

92e43d8bcd185f4505abf543e92348d4.png

2.2 被卡住的情况

?源码及效果展示 https://jsbin.com/tapidetiyi/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bintitle>
head>
<body>
  <div class="ct">
    <div class="box box1">①div>
    <div class="box box2">②div>
    <div class="box box3">③div>
  div>
body>
html>
CSS

.ct {width: 280px;height: 300px;border: 1px solid;margin: 100px;
}.box {color: #fff;width: 100px;height: 100px;background: red;float: left;
}.box1 {background: blue;height: 120px;
}.box2 {background: pink;
}/*
依然站在浏览器的角度,从上往下渲染文档,
当依次渲染完 1、2 后,渲染 3 的时候,右边放不下,
然后它要被挤下去,挤下去后它贴着 2 的下边缘开始向左移动,
当移动碰到 1 右下角时,动不了了,1 被卡住了。
所以我们在设置高度不一样时,会出现一个“卡住”的问题。
 */

a9788bfffc658abb8648e1e3d8541cd3.png

2.3 当浮动元素与文本有交集的时候

?源码及效果展示 https://jsbin.com/pacuvusoja/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bintitle>
head>
<body>
  <div class="ct">
    <div class="box box1">①div>
    <p>
      挨到包含块边沿或者另一个浮动盒的外边。
      如果存在行盒,浮动盒的外 top(边)会与当前行盒的 top(边)对齐。
      如果没有足够的水平空间来浮动,它会向下移动,
      直到空间合适或者不会再出现其他浮动了。
    p>
    <div class="box box2">②div>
    <div class="box box3">③div>
  div>
body>
html>
CSS

.ct {width: 280px;height: 300px;margin: 100px;border: 1px solid black;
}.box {float: left;width: 100px;height: 100px;background: red;color: #fff;
}.box1 {width: 140px;height: 120px;background: blue;
}.box2 {background: pink;
}

90587b8f8fc48e40c696b381fcb6af63.png

?可以得到:
普通流中的一个元素,如果没有设置定位和浮动,那它和浮动元素在一起之后,它会被浮动元素所遮挡。

?进一步验证:
?源码及效果展示 https://jsbin.com/yijajakaxo/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bintitle>
head>
<body>
  <div class="ct">
    <div class="box box1">①div>
    <p>
      挨到包含块边沿或者另一个浮动盒的外边。
      如果存在行盒,浮动盒的外 top(边)会与当前行盒的 top(边)对齐。
      如果没有足够的水平空间来浮动,它会向下移动,
      直到空间合适或者不会再出现其他浮动了。
    p>
    <div class="box box2">②div>
    <div class="box box3">③div>
  div>
body>
html>
CSS

.ct {width: 280px;height: 300px;margin: 100px;border: 1px solid;
}.box {float: left;width: 100px;height: 100px;background: red;
}.box1 {width: 140px;height: 120px;background: blue;opacity: 0.5; /* ?设置透明度来观察! */
}.box2 {background: pink;
}/*
?但里边的文字并没有被这个浮动元素所遮挡,那他呈现的这个效果是:
这个段落 p 是看不到这个浮动元素的,而文字看得到,并且围绕这个浮动元素排列。
 *//*
?即展现出来的一个规则就是:
当一个普通元素碰到一个浮动元素后,这个普通元素看不见这个浮动元素,
但普通元素里边的文字看得见这个浮动元素。
 */

8f76453e0a0b80e1dc2a3a363fb81a05.png

2.4 浮动元素脱离了普通流

脱离普通流是指:它的父容器在去计算宽高的时候,发现不了浮动元素。即,父容器不会被里面的浮动元素撑开;

❗️ 注意:和 absolute 不一样。
?源码及效果展示 https://jsbin.com/kuqejusoto/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>前端一万小时title>
head>
<body>
  <div class="ct">
    <div class="box box1">①div>
    <div class="box box2">② 块盒看不见浮动的 box1,但我是文本我能看见!div>
    <div class="box box3">③div>
  div>
body>
html>
CSS

.ct {width: 280px;height: 300px;margin: 100px;border: 1px solid;
}.box {width: 100px;height: 100px;background: red;color: #fff;
}.box1 {float: left;background: blue;opacity: 0.6;
}.box2 {width: 110px;height: 110px;background: pink;
}

17f277ac810e796985ecef7f7de93dca.png

2.5 块级元素浮动宽度收缩,行内元素浮动以块级特性去呈现

?源码及效果展示 https://jsbin.com/sotonifaqu/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bintitle>
head>
<body>
  <div class="box">这是 divdiv>
  <span>这是 spanspan>
body>
html>
CSS

.box {float: left;color: #fff;background: red;
}span {float: left;width: 100px;height: 50px;margin: 10px;color: #fff;background: blue;
} /* ?块级元素设置浮动之后,它就呈现出 inline-block 这种感觉,它的宽度会收缩。 *//*
?行内元素设置为浮动之后,它就呈现了块级的特性,也有 inline-block 的感觉,
就把行内元素变成可以设置宽高、margin 等,但没有居中这些东西。
 */

780f8fbe915e476319d10c8090a41db8.png

3 “浮动”的使用场景

3.1 两栏布局(左侧固定宽度,右侧自适应;右侧固定宽度,左侧自适应)

?源码及效果展示——左侧固定宽度,右侧自适应 https://jsbin.com/hamakucaye/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bintitle>
head>
<body>
  <div class="aside">侧边栏固定宽度div>
  <div class="main">内容区块自适应宽度div>
body>
html>
CSS

.aside {float: left;width: 150px;height: 400px;color: #fff;background: red;
}.main {height: 500px;margin-left: 160px; /* ?表示左边的这 160px 的范围我不用了! */color: #fff;background: blue;
}

8ed82307e2967d4ae9f232e5fd35b893.png

?对比(右侧固定宽度,左侧自适应):
?源码及效果展示 https://jsbin.com/cafohunara/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>前端一万小时title>
head>
<body>
  <div class="aside">侧边栏固定宽度div>
  <div class="main">内容区块自适应宽度div>
body>
html>
CSS

.aside {float: right;width: 150px;height: 400px;color: #fff;background: red;
}.main {margin-right: 160px;/* ?表示右边的这 160px 的范围我不用了! */height: 500px;color: #fff;background: blue;
}

0829441dd37962da14cb7a7eedd6c6e0.png

3.2 三栏布局——两侧宽度固定,中间自适应(注意 HTML 中的 menu aside main 的顺序!)

?源码及效果展示 https://jsbin.com/vusaxoyiwi/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>前端一万小时title>
head>
<body>
  <div class="menu">侧边栏固定宽度div>
  <div class="aside">侧边栏固定宽度div>
  <div class="main">内容区块自适应宽度div>
body>
html>
CSS

.menu {float: left;width: 150px;height: 400px;color: #fff;background: red;
}.aside { float: right;width: 150px;height: 400px;color: #fff;background: red;
}.main {height: 500px;margin-right: 160px;margin-left: 160px;/* ?加左右 margin 就把位置撑开了! */color: #fff;background: blue;
}

c398289a8d7bb7f5a4dc9382684fc193.png

❗️ 如果 HTML 中的 menu aside main 的顺序变了:
?源码及效果展示 https://jsbin.com/rowemavuwe/edit?html,css,output

HTML

<div class="menu">侧边栏固定宽度div>
<div class="main">内容区块自适应宽度div>
<div class="aside">侧边栏固定宽度div>


CSS

.menu {float: left;width: 150px;height: 400px;color: #fff;background: red;
}.aside { float: right;width: 150px;height: 400px;color: #fff;background: red;
}.main {height: 500px;margin-right: 160px;margin-left: 160px;/* 加左右 margin 就把位置撑开了! */color: #fff;background: blue;
}

9f44dc248428da71ddc6aa803727bb63.png

3.3 利用浮动实现“导航条”

3.3.1 “导航条”靠左
?源码及效果展示 https://jsbin.com/nofezuxidu/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bintitle>
head>
<body>
  <ul class="navbar">
    <li><a href="#">① 首页a>li>
    <li><a href="#">② 产品a>li>
    <li><a href="#">③ 服务a>li>
    <li><a href="#">④ 关于a>li>
  ul>
body>
html>
CSS

.navbar {list-style: none;
}.navbar>li {float: left;margin-left: 15px;
}/*
?当然我们用 inline-block 也可以实现效果,但不同方式需要注意的问题不一样:
使用浮动我们需要注意撑开容器;而用 inline-block,我们需要注意它的缝隙。
 */

c179658694ddedfd6b270a39d1ad92cf.png

3.3.2 “导航条”靠右
?源码及效果展示 https://jsbin.com/feyaposiko/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>前端一万小时title>
head>
<body>
  <ul class="navbar">
    <li><a href="#">① 首页a>li>
    <li><a href="#">② 产品a>li>
    <li><a href="#">③ 服务a>li>
    <li><a href="#">④ 关于a>li>
  ul>
body>
html>
CSS

.navbar {float: right;/* ?把 ul 整体进行右浮动。 */list-style: none;
}.navbar>li {float: left;/* ?但 ul 里边的东西都是靠左的。 */margin-left: 15px;
}

837ee78e5f7601eeb2c6469fc0a53ff9.png

?对比:
?源码及效果展示 https://jsbin.com/vevoyevoha/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>前端一万小时title>
head>
<body>
  <ul class="navbar">
    <li><a href="#">① 首页a>li>
    <li><a href="#">② 产品a>li>
    <li><a href="#">③ 服务a>li>
    <li><a href="#">④ 关于a>li>
  ul>
body>
html>
CSS

.navbar {list-style: none;
}.navbar>li {float: right;/* ?直接改这里是不行的,因为站在浏览器的立场是按文档顺序来渲染的。 */margin-left: 15px;
}

af38bfd9e818049b3cde5b650f98fb0e.png

4 清除“浮动”

4.1 为什么要清除浮动

因为任何东西有利有弊。

4.1.1 第一,浮动对后续元素位置产生影响(渲染时,因为块元素看不见,但里边的文字看的见)
?源码及效果展示 https://jsbin.com/hifubizayu/edit?html,css,output

HTML

<div id="content">
  <div class="menu">侧边栏固定宽度div>
  <div class="aside">侧边栏固定宽度div>
  <div class="main">内容区块自适应宽度div>
div>
<div id="footer">我是 footer,但我的样式出现了问题!div>
CSS

.menu {float: left;width: 150px;height: 300px;color: #fff;background: red;
}.aside { float: right;width: 150px;height: 300px;color: #fff;background: red;
}.main {height: 200px;margin-right: 160px;margin-left: 160px;color: #fff;background: blue;
}#footer {color: #fff;background: grey;
}

1026cafa3bb9809e4719455c20c389b1.png

3e2e6e64450ce778b196d470c1f22f57.png

4.1.2 第二,父容器高度计算出现问题
?源码及效果展示 https://jsbin.com/guqobomewe/edit?html,css,output

HTML

html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>前端一万小时title>
head>
<body>
  <ul class="navbar">
    <li><a href="#">① 首页a>li>
    <li><a href="#">② 产品a>li>
    <li><a href="#">③ 服务a>li>
    <li><a href="#">④ 关于a>li>
  ul>
body>
html>
CSS
.navbar {list-style: none;border: 1px solid #ccc;/*
  加一个背景色也没效果:
  background: pink;
   */
}.navbar>li {float: left;margin-left: 15px;
}/*
?由于浮动元素脱离了文档流,所以它的父元素是看不见他的。
这里对于 navbar 来说,它认为里边没有什么 li 来把它撑开,
因为 li 已经浮动了,那没有东西撑开它,它就会认为高度为 0。
 */

d54feb90d227db925362549095005749.png

4.2 清除浮动的方法

4.2.1 清除浮动实现的原理和方法

?源码及效果展示https://jsbin.com/behomudiji/edit?html,css,output

HTML
<ul class="navbar">
  <li><a href="#">① 首页a>li>
  <li><a href="#">② 产品a>li>
  <li><a href="#">③ 服务a>li>
  <li><a href="#">④ 关于a>li>

  <li class="clear">li>
   

ul>
CSS

.navbar {list-style: none;border: 1px solid #ccc;
}.navbar>li {float: left;margin-left: 15px;
}.navbar .clear {float: none;clear: left;
}/* ?通过清除浮动来获得一个普通元素,进而撑开这个父容器。 */

f8c96af5d8cef98a94e1aa2002701437.png

  • 清除浮动 clear: left; ——这个 clear 可以用在任何元素上,不管你是不是浮动元素。要求该盒的 top、border 边位于源文档(就是 HTML 文档结构中)中在此之前的元素形成的所有左浮动盒的 bottom 外边下方(如果没有左浮动盒,那你清除左浮动也就没有意义)。

  • 清除浮动 clear: right; ——要求该盒的 top border 边位于源文档中在此之前的元素形成的所有右浮动盒的 bottom 外边下方。

  • 清除浮动 clear: both; ——只要源文档中该盒前边有浮动元素,那么就在这个浮动元素下方。

1. ?对比

我们上边是用一个 li 来实体化普通元素,那我们可否有更简化的方法——伪元素(伪元素的一个作用就是去代替标签)。

?源码及效果展示 https://jsbin.com/quhuzureqa/edit?html,css,output

HTML

<ul class="navbar">
  <li><a href="#">① 首页a>li>
  <li><a href="#">② 产品a>li>
  <li><a href="#">③ 服务a>li>
  <li><a href="#">④ 关于a>li>
ul>
CSS

.navbar {list-style: none;border: 1px solid #ccc;
}.navbar>li {float: left;margin-left: 15px;
}.navbar::after {content: "";/* ?写了一个元素,你必须要有 content。 */display: block;/*
  ?注意这里如果没有这个 block,是不会生效的,因为写了 after,只是表示是一个匿名的行盒,
  即一个字符串。然而它必须是块级元素,它才会下去。
   */clear: both;
}/*
?用伪元素这样写就是表示:
我在源文档 navbar 的最后生成了一个 block 元素,然后清除浮动,它就会位于浮动盒子的下方,
进而撑开了 navbar 这个父容器。
 */

da9f1524c9399bf898639d7fba044256.png

2. ?再对比
?源码及效果展示 https://jsbin.com/cicowelebo/edit?html,css,output

为了通用性,我们常常 .clearfix::after; ——就是为了修复浮动所产生的问题。

HTML

<ul class="navbar clearfix">


  <li><a href="#">① 首页a>li>
  <li><a href="#">② 产品a>li>
  <li><a href="#">③ 服务a>li>
  <li><a href="#">④ 关于a>li>
ul>
CSS

.navbar {list-style: none;border: 1px solid #ccc;
}.navbar>li {float: left;margin-left: 15px;
}.clearfix::after {/*
  ?为了通用性,我们直接 clearfix。然后在 HTML 文档中,
  哪里需要清除浮动,就直接加一个这个类名进去就可以了。
   */content: "";display: block;clear: both;
}

1c81e4d197a0feb5266fa73a39397349.png

4.2.2 解决上边由“浮动”带来的问题
?源码及效果展示 https://jsbin.com/tayicumolu/edit?html,css,output

HTML

<div id="content" class="clearfix">


  <div class="menu">侧边栏固定宽度div>
  <div class="aside">侧边栏固定宽度div>
  <div class="main">内容区块自适应宽度div>
div>
<div id="footer">我是 footer,但我的样式出现了问题!div>
CSS

.menu {float: left;width: 150px;height: 300px;color: #fff;background: red;
}.aside { float: right;width: 150px;height: 300px;color: #fff;background: red;
}.main {height: 200px;margin-right: 160px;margin-left: 160px;color: #fff;background: blue;
}#footer {color: #fff;background: grey;
}.clearfix::after {/*
  ?为了通用性,我们直接 clearfix,然后在 HTML 文档中,哪里需要清除浮动,
  就直接加一个这个类名进去就可以了。
   */content: "";display: block;clear: both;
}

ff97f6981bc0c4dfa0d162ec8a1baa6b.png

?小总结:
所以以后我们想去实现一个水平布局,就有了两种方法:

  • 第一,inline-block——不需要清除浮动,简单,在设置居中时更方便,适合子内容不多的元素水平排列。但要注意缝隙问题,以及对齐(上对齐);

  • 第二,float——没缝隙问题,适合稍大的布局。但需要解决的问题是父元素不会被撑开而导致的很多问题。

5 浮动和负 margin

两个浮动元素,如果因放不下导致其中一个下移,对下移的元素设置负 margin 值大于自身的宽度可将其上移。

?源码及效果展示 https://jsbin.com/divuquneko/edit?html,css,output

HTML

<div class="container">
  <div class="box box1">box1div>
  <div class="box box2">box2div>
div>
CSS

* {margin: 0
}.container {width: 400px;height: 400px;border: 1px solid red;
}.box1 {float: left;width: 300px;height: 100px;background: pink;
}.box2 {float: left;width: 110px;height: 100px;margin-left: -10px;  /* ?浏览器计算的时候就相当于宽度减去这个 10,然后就是 100,那就正好放上去。 */background-color: red;
}

1492c3ad9a61d288d16a0be322938c47.gif


后记:下篇我们将讨论与“浮动”对应的“定位”是怎样让“盒子”动起来的。后续文章都是重中之重,每一篇都干货满满!

祝好,qdywxs ♥ you!

69c41e7fe8147d7cafd9cecb69145424.gif 点击“
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐