主题
Flex 布局(三)
本页对应 Flex 布局,共 7 段视频,约 1 小时 3 分。
学习目标
- 能独立完成小米右侧 8 个小盒子的结构与样式,设置每个小盒子 234×300,并解释 978 宽度下 4 个一行的计算依据。
- 能复现并解释浮动元素脱标导致父容器高度塌陷、下方盒子上升的现象,并说明其产生原因。
- 能使用额外标签法、单/双伪元素法、父级
overflow: hidden等方式为指定父容器清除浮动,并能识别常见clearfix写法。 - 能说明浮动的本质是图文混排,并使用
float实现图片被文字环绕的效果。 - 能使用
display: flex将子元素排列到一行,并说明弹性容器、弹性盒子、主轴与侧轴的基本概念。 - 能使用
justify-content的flex-start、flex-end、center、space-between、space-around、space-evenly实现指定主轴排列,并区分不同间距分布规律。
知识点
浮动的基本使用
为什么需要:块元素默认从上往下排,想让多个块元素水平排列时,可以用浮动。怎么想:给需要并排的盒子加 float,left 左对齐,right 右对齐。怎么做:属性名是 float,属性值常用 left、right。示例代码保留如下:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>浮动</title>
<style>
.left,
.right {
/* width: 200px; */
height: 200px;
background-color: pink;
}
.left {
/* 左浮动 */
float: left;
margin-left: 20px;
}
.right {
/* 右侧浮动 */
float: left;
height: 300px;
background-color: purple;
}
.bottom {
height: 50px;
background-color: black;
}
</style>
</head>
<body>
<div class="left">左侧123</div>
<div class="right">右侧123</div>
<div class="bottom"></div>
</body>
</html>特点:浮动后的盒子顶对齐;具备行内块特点,可以设宽高;浮动后的盒子脱标,不占标准流的位置。
易错点:示例里 .right 实际写的是 float: left,所以两个盒子都左浮动;如果要右对齐,应写 float: right。另外,浮动后脱标,父级若没有高度,可能撑不开父级。
产品区域左右布局
为什么需要:产品区域常见“左侧菜单 + 右侧内容”的结构。怎么想:外层一个大盒子,里面放左右两个盒子,分别浮动到左右两侧。怎么做:HTML 结构如下:
html
<div class="mi">
<div class="left">左侧</div>
<div class="right">右侧</div>
</div>CSS 样式:
html
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
li {
list-style: none;
}
.mi {
width: 1226px;
height: 614px;
/* background-color: pink; */
margin: 100px auto;
}
.left {
float: left;
width: 234px;
height: 614px;
background-color: skyblue;
}
.right {
float: right;
width: 978px;
height: 614px;
background-color: purple;
}
</style>效果:
易错点:左侧 float: left,右侧要 float: right;父容器总宽度要能容纳左右宽度,否则右侧会掉下去。
区域小li布局
为什么需要:右侧区域要放 8 个小商品块,并排成四列两行。怎么想:先让 li 左浮动,再给小 li 设宽高和间距。推导时注意:右侧宽 978px,小 li 宽 234px,间距 14px。四个 li 加三个间距是 234×4 + 14×3 = 978;如果每个 li 都加右外边距,就变成 234×4 + 14×4 = 992,超过 978,一行装不下四个,所以第 4、8 个要去掉右外边距。完整写法:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
li {
list-style: none;
}
.mi {
width: 1226px;
height: 614px;
/* background-color: pink; */
margin: 100px auto;
}
.left {
float: left;
width: 234px;
height: 614px;
background-color: skyblue;
}
.right {
float: right;
width: 978px;
height: 614px;
/* background-color: purple; */
}
.right li {
float: left;
width: 234px;
height: 300px;
background-color: pink;
margin-bottom: 14px;
margin-right: 14px;
}
/* 让第4,8 个li 去掉外边距 */
.right li:nth-child(4n) {
margin-right: 0;
}
</style>
</head>
<body>
<div class="mi">
<div class="left">左侧</div>
<div class="right">
<ul>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
</ul>
</div>
</div>
</body>
</html>
易错点:选择器要限定为 .right li,不要写成全局 li;nth-child(4n) 用来选第 4、8 个;宽度和间距差一像素都可能导致换行。
清除浮动:问题从哪来
为什么需要:浮动元素脱标,不占标准流位置;如果父级没有高度,子级无法撑开父级高度,下面的盒子就会升上来。怎么想:先搭出父级无高度、子级左右浮动的场景,再观察 .bottom 上移。场景代码:
html
<style>
.top {
margin: 10px auto;
width: 1200px;
/* height: 300px; */
background-color: pink;
}
.left {
float: left;
width: 200px;
height: 300px;
background-color: skyblue;
}
.right {
float: right;
width: 950px;
height: 300px;
background-color: orange;
}
.bottom {
height: 100px;
background-color: brown;
}
</style>
<div class="top">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="bottom"></div>
易错点:清除浮动不是“清除浮动元素”,而是清除浮动带来的高度塌陷影响;父级能直接给高度时问题会消失,但很多场景父级不方便给固定高度。
清除浮动的四种写法
额外标签法:在父元素内容的最后添加一个块级元素,设置 clear: both。
html
<style>
.clearfix {
clear: both;
}
</style>
<div class="father">
<div class="left"></div>
<div class="right"></div>
<div class="clearfix"></div>
</div>易错点:必须是块级元素;clear: both 清除左右浮动影响。
单伪元素法:用 ::after 在父元素最后生成一个块级盒子。
css
.clearfix::after {
content: "";
display: block;
clear: both;
}html
<div class="father clearfix"></div>易错点:content、display: block、clear: both 三句都要有,缺一不可。
双伪元素法:before 解决外边距塌陷,after 清除浮动。
css
/* before 解决外边距塌陷问题 */
/* 双伪元素法 */
.clearfix::before,
.clearfix::after {
content: "";
display: table;
}
/* after 清除浮动 */
.clearfix::after {
clear: both;
}html
<div class="father clearfix"></div>易错点:before 和 after 都要写;display: table 与 clear: both 分工不同。
overflow法:直接给父元素加 overflow: hidden。
css
.father {
margin: 10px auto;
width: 1200px;
/* height: 300px; */
background-color: pink;
overflow: hidden;
}易错点:overflow: hidden 会裁剪超出父盒子的内容;父级有固定高度时,孩子超出会被隐藏,但不会把下面盒子挤下去。
本节图示

Flex布局是什么
Flex 布局也叫弹性布局,是浏览器提倡的布局模型,非常适合结构化布局,提供了强大的空间分布和对齐能力。转写稿里把 flex 说成“flash”,是同音口误,实际属性是 display: flex。Flex 模型不会产生浮动布局中脱标现象,布局网页更简单、更灵活。转写中用小米右侧 8 个小盒子演示过:浮动后子级脱标,父级若没有高度就撑不开,底部盒子会升上来;而 Flex 不脱标,所以不用再走“清除浮动”那一套。

为什么需要:以前想把多个块级盒子放一行,常用浮动,但浮动会脱标,父级高度可能塌陷。
怎么想:Flex 的核心思路是“父级控制子级”,必须先有弹性容器。
怎么做:给父元素设置 display: flex,子元素可以自动挤压或拉伸。
易错点:不是给子元素加 display: flex 来控制自己排列;使用 Flex 排列的前提是有父容器。
Flex组成
设置方式:给父元素设置 display: flex,子元素可以自动挤压或拉伸。组成部分包括:弹性容器、弹性盒子、主轴(默认在水平方向)、侧轴 / 交叉轴(默认在垂直方向)。

为什么需要:不理解“容器、盒子、主轴、侧轴”,后面 justify-content 和 align-items 很容易写反。
怎么想:父盒子叫弹性容器,子盒子叫弹性盒子;默认主轴水平,侧轴垂直。
怎么做:先写父级 display: flex,再分别记:主轴对齐用 justify-content,侧轴对齐用 align-items。
易错点:默认主轴是水平方向,不代表所有场景永远水平;本节先按默认轴理解。转写中反复强调“通过父亲控制孩子”,实际就是父级控制子级。
主轴对齐方式
属性名:justify-content。

重点记住标红的。如果非要问哪个常用,是 space-between。
css
justify-content: space-between;显示效果:两侧没缝隙。

css
justify-content: space-around;效果如下:记住2倍。

css
justify-content: space-evenly;效果如下:记住空隙一样大。

css
justify-content: center;效果如下:经常用于让一个盒子水平居中。

记忆:两侧没缝隙是 between;缝隙一样大是 evenly;2倍缝隙是 around。转写中演示时,先给父级加 display: flex,三个子盒子立刻一行;再切换 justify-content 观察分布变化。小米这类两侧贴边、中间留缝的结构,常用 space-between。
为什么需要:只写 display: flex 时子项默认挤在主轴起始位置,页面不一定好看。
怎么想:把剩余空间怎么分——贴两边用 between,均匀空隙用 evenly,盒子两侧都有空隙且中间约为两边两倍用 around,整体居中用 center。
怎么做:在弹性容器上写 justify-content。
易错点:space-between 是两侧没缝隙;space-around 不是完全等距,而是每个盒子左右都有相等空隙,视觉上中间约为两边两倍;space-evenly 才是所有空隙一样大。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
/* 给父亲添加 flex */
display: flex;
/* 主轴的排列方式 */
/* justify-content: flex-start; */
/* justify-content: flex-end; */
/* 让子盒子居中对齐 */
/* justify-content: center; */
/* between */
/* justify-content: space-between; */
/* justify-content: space-around; */
justify-content: space-evenly;
width: 900px;
height: 200px;
background-color: pink;
}
.box div {
width: 249px;
height: 200px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="box">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</body>
</html>
侧轴对齐方式
align-items:当前弹性容器内所有弹性盒子的侧轴对齐方式(给弹性容器设置)align-self:单独控制某个弹性盒子的侧轴对齐方式(给弹性盒子设置)

为什么需要:主轴只管一行里的左右分布,盒子在上下方向的对齐要靠侧轴属性。
怎么想:统一控制所有子项用 align-items;只改某一个子项用 align-self。
怎么做:在父级写 align-items: flex-start / flex-end / center / stretch。
易错点:stretch 是默认值,子盒子不写高度时会拉伸到与父级一样高;转写中演示过,父级有高度时子项可被拉伸,父级没高度时也会受内容影响。align-self 不要写到父级上。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
/* 给父亲添加 flex */
display: flex;
/* 主轴的排列方式 */
/* justify-content: flex-start; */
/* justify-content: flex-end; */
/* 让子盒子居中对齐 */
/* justify-content: center; */
/* between */
/* 两侧没缝隙 */
/* justify-content: space-between; */
/* 两倍缝隙 */
/* justify-content: space-around; */
justify-content: space-evenly;
/* 侧轴的对齐方式 */
/* 顶部对齐 */
/* align-items: flex-start; */
/* 底部对齐 */
/* align-items: flex-end; */
/* 居中对齐 */
/* align-items: center; */
/* 默认的 拉伸和父亲一样 */
align-items: stretch;
width: 900px;
height: 500px;
background-color: pink;
}
.box div {
width: 249px;
/* height: 200px; */
background-color: skyblue;
}
</style>
</head>
<body>
<div class="box">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</body>
</html>
盒子水平和垂直居中的写法

为什么需要:传统写法让一个盒子在父级中水平垂直居中比较绕,Flex 两行就能完成。
怎么想:默认主轴水平,所以 justify-content: center 管水平居中;侧轴垂直,所以 align-items: center 管垂直居中。
怎么做:父级写 display: flex; justify-content: center; align-items: center;。
易错点:两个属性都写在父级;不要把 justify-content 和 align-items 的作用轴记反。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.father {
/* 利用flex实现 */
display: flex;
/* 主轴水平居中 */
justify-content: center;
/* 侧轴水平居中 */
align-items: center;
width: 300px;
height: 300px;
background-color: pink;
}
.son {
width: 200px;
height: 200px;
background-color: purple;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
</body>
</html>代码示例
示例 1:浮动基本使用
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>浮动</title>
<style>
.left,
.right {
/* width: 200px; */
height: 200px;
background-color: pink;
}
.left {
/* 左浮动 */
float: left;
margin-left: 20px;
}
.right {
/* 左侧浮动 */
float: left;
height: 300px;
background-color: purple;
}
.bottom {
height: 50px;
background-color: black;
}
</style>
</head>
<body>
<div class="left">左侧123</div>
<div class="right">右侧123</div>
<div class="bottom"></div>
</body>
</html>要点解释
float: left让块元素水平排列,取值只有left/right,没有center,也不存在“居中浮动”。- 浮动后的盒子顶对齐、具备行内块特点(可给宽高、不换行)、并且脱标,不占用标准流位置。
- 这里
.left/.right的width被注释掉了,宽度由内容撑开;把注释打开才固定为 200px。 - 易错点:
.bottom是标准流盒子,会钻到浮动盒子下面(被.right的 300px 高度盖住),这就是后面要“清除浮动”的原因;另外父级没有高度时,浮动的子级无法撑开父级高度。
示例 2:产品区域(小米)左右布局 + 小 li 布局
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
li {
list-style: none;
}
.mi {
width: 1226px;
height: 614px;
/* background-color: pink; */
margin: 100px auto;
}
.left {
float: left;
width: 234px;
height: 614px;
background-color: skyblue;
}
.right {
float: right;
width: 978px;
height: 614px;
/* background-color: purple; */
}
.right li {
float: left;
width: 234px;
height: 300px;
background-color: pink;
margin-bottom: 14px;
margin-right: 14px;
}
/* 让第4,8 个li 去掉外边距 */
.right li:nth-child(4n) {
margin-right: 0;
}
</style>
</head>
<body>
<div class="mi">
<div class="left">左侧</div>
<div class="right">
<ul>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
</ul>
</div>
</div>
</body>
</html>要点解释
- 大盒子
.mi宽 1226px,用margin: 100px auto水平居中;左侧 234px 左浮动,右侧 978px 右浮动,正好铺满。 - 结构位置不能写错:8 个
li是放在.right里面的ul中,选择器写.right li才生效。 - 关键算式(易错点):
234 + 14 = 248,248 × 4 = 992 > 978,所以一行放不下 4 个,会掉行。必须用:nth-child(4n)把第 4、8 个li的右外边距强制改为 0,这样234×4 + 14×3 = 978才能正好一行 4 个,一像素都不能多、不能少。 margin-bottom: 14px全部保留(第二排下方的间距不影响布局);如果觉得底部多出 14px 别扭,可以再给父级加overflow: hidden切掉。
示例 3:Flex 主轴对齐 + 侧轴对齐
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
/* 给父亲添加 flex */
display: flex;
/* 主轴的排列方式 */
/* justify-content: flex-start; */
/* justify-content: flex-end; */
/* 让子盒子居中对齐 */
/* justify-content: center; */
/* 两侧没缝隙 */
/* justify-content: space-between; */
/* 两倍缝隙 */
/* justify-content: space-around; */
justify-content: space-evenly;
/* 侧轴的对齐方式 */
/* 顶部对齐 */
/* align-items: flex-start; */
/* 底部对齐 */
/* align-items: flex-end; */
/* 居中对齐 */
/* align-items: center; */
/* 默认的 拉伸和父亲一样 */
align-items: stretch;
width: 900px;
height: 500px;
background-color: pink;
}
.box div {
width: 249px;
/* height: 200px; */
background-color: skyblue;
}
</style>
</head>
<body>
<div class="box">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</body>
</html>要点解释
display: flex必须写在父级(弹性容器)上,子元素(弹性盒子)才会自动在一行上挤压/拉伸;写在子元素上无效。justify-content控制主轴(默认水平)对齐:flex-start/flex-end/center/space-between(两侧没缝隙,最常用)/space-around(两侧缝隙是中间的 2 倍)/space-evenly(缝隙一样大)。align-items控制侧轴(默认垂直)对齐,作用于容器内所有弹性盒子;单个盒子可用align-self单独设置。- 易错点:
.box div的height被注释掉后,默认align-items: stretch会让子盒子自动拉伸到和父亲一样高,所以看不到 200px 的高度效果;把height: 200px打开或改成align-items: center才能看出差别。 - 补充(笔记同款写法):盒子水平垂直居中只需在父级写
display: flex; justify-content: center; align-items: center;;Flex 布局不脱标,不会出现浮动那种父级高度塌陷,也就无需清除浮动。
常见错误
现象:父级没有高度,子元素浮动后父级“塌陷”,底部盒子升上来。
原因:浮动元素脱标,不占标准流位置,无法撑开父级高度。
修法:给父级清除浮动(双伪元素 clearfix / overflow:hidden / 额外标签法),或改用 Flex 布局。现象:一行本应放 4 个商品卡,结果只放 3 个或最后一个掉行。
原因:子项宽度 + margin 总和超过父容器宽度,例如 234×4 + 14×4 > 978。
修法:去掉每行最后一个的右 margin,如.right li:nth-child(4n){margin-right:0};更推荐 Flex +gap。现象:给子元素写
display:flex,布局没有按预期横向排列。
原因:Flex 是“父控子”,display:flex应写在弹性容器(父级)上。
修法:把display:flex写到父容器,子项自动成为弹性盒子。现象:想实现盒子水平垂直居中,只写了一个对齐属性,结果只居中一个方向。
原因:主轴对齐和侧轴对齐分工不同,且必须作用于弹性容器。
修法:父级同时写display:flex; justify-content:center; align-items:center;。现象:写了
::after{clear:both}但清除浮动无效。
原因:伪元素缺少content,或仍是行内元素,未形成块级盒子。
修法:使用完整写法:content:""; display:block; clear:both;。
练习
用 Flex 实现:父容器内 3 个盒子横向排列,两端贴边、中间间距均分,且所有盒子在父容器内垂直居中。写出父级关键 CSS。
用浮动完成 2 行 4 列商品卡布局:每个卡片宽 234px、高 300px,右间距和下间距均为 14px,要求每行第 4 个卡片没有右间距。写出关键选择器和清除浮动方案。
给定结构:父级无高度,内部两个浮动子元素,下面还有一个底部盒子。分别用“双伪元素法”和“overflow 法”修复布局,并说明两种方案的使用差异。
父容器内有 3 个子项,分别设置
justify-content: space-between / space-around / space-evenly,画出或描述三种间距关系,并写出你的记忆规则。把第 2 题的商品卡浮动布局改造成 Flex 布局,要求实现同样的 4 列排列和 14px 间距,并说明改造后为什么不再需要清除浮动。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 小米模块布局下 | 09:04 |
| 2 | 小问题 | 04:19 |
| 3 | 清除浮动 | 21:37 |
| 4 | 浮动的本质 | 04:05 |
| 5 | flex布局认识 | 04:27 |
| 6 | flex布局体验 | 02:05 |
| 7 | 主轴的排列方式 | 17:42 |
小结
- 浮动只需了解,现代布局优先使用 Flex。
- 浮动脱标是父级塌陷、底部盒子上移的根源。
- 清除浮动清除的是“浮动带来的布局影响”,不是取消浮动本身。
- Flex 的核心是父容器控制子项,
display:flex写在父级。 - 主轴排列看
justify-content,侧轴对齐看align-items / align-self。 space-between最常用;space-around记两倍关系;space-evenly记间距均等。- 商品卡多列布局优先用 Flex +
gap,比浮动逐项处理 margin 更稳。 - clearfix 必须满足:生成内容、块级显示、
clear:both。