主题
伸缩盒布局 Flex(Day15 3/3)
本页对应 Day15_CSS3,共 7 段视频,约 1 小时 5 分。
学习目标
- 能够使用 Flex 布局实现子元素在父容器中水平垂直居中,并说明
justify-content、align-items与margin: auto两种方案的实现条件。 - 能够列举设置给伸缩容器的 7 个常用 CSS 属性及其作用,并正确区分伸缩容器与伸缩项目的属性设置对象。
- 能够根据
flex-grow、flex-shrink和项目原主轴长度计算扩展或收缩后的主轴尺寸,并解释扩展与收缩计算规则的差异。 - 能够使用
order调整伸缩项目排序,使用align-self单独设置某个伸缩项目的侧轴对齐方式,并说明其默认值auto的含义。 - 能够解释
flex: 1、flex: auto、flex: 0 auto等简写对扩展、收缩和主轴基础长度的影响,并说明伸缩项目布局中内容最小宽度与不换行的限制。 - 能够说明主侧轴对齐方式作用于文字的条件,并在无子元素但有文本内容的伸缩容器中验证文字居中效果。
知识点
一、用 Flex 实现元素居中:为什么需要、怎么想、怎么做、易错点
为什么需要:传统用定位加位移居中,往往要算尺寸;Flex 在没有固定宽高的场景下更直接。
怎么想:要让 .book 成为伸缩项目,先把它的父元素 body 变成伸缩容器;容器没高度时,html、body 都要设 height:100%,否则侧轴没有可居中的空间。
怎么做:方案一给容器设主轴、侧轴居中;方案二给项目设 margin:auto。
css
html, body { height: 100%; margin: 0; }
body { display: flex; justify-content: center; align-items: center; }
.book { width: 400px; padding: 20px; color: #fff; }
/* 方案二:body 仍为 flex,.book 改为 margin:auto */转写稿调试时出现竖向滚动条,原因是 body 自带外边距,设 margin:0 后消失;.book 不设高会被内容撑开,但作为伸缩项目若不设固定长度,侧轴可能被拉伸,所以要用 align-items:center 而不是默认 stretch。
易错点:只给 body 设 height:100% 不够;margin:auto 在普通块级中通常只能水平居中,在伸缩项目里四个方向都有效,但前提是父元素为伸缩容器。
二、主侧轴对齐方式作用于文字
为什么需要:容器没有子元素、只有文字时,也可能想让文字居中。
怎么想:把有文字的容器设为 display:flex,虽无伸缩项目,但对齐方式仍可作用于文字。
怎么做:
css
.book {
width: 600px; height: 300px; background: #900; color: #fff;
display: flex; justify-content: center; align-items: center;
}易错点:这是特性,不是常规首选;普通文字居中用 text-align、line-height 更直接。知道“有效”即可,别把它当主要布局手段。
三、设置给伸缩容器的相关属性
为什么需要:属性设错对象就不好使,先分清“给容器”还是“给项目”。
怎么想:容器属性控制显示模式、主轴方向、换行和对齐。
怎么做:常总结 7 个:display:flex/inline-flex;flex-direction:row/row-reverse/column/column-reverse;flex-wrap:nowrap/wrap/wrap-reverse;flex-flow 同时设方向和换行;justify-content:flex-start/flex-end/center/space-between/space-around/space-evenly;align-items:stretch/flex-start/flex-end/center/baseline;align-content 作用于多行侧轴对齐。
易错点:align-content 不换行时没有效果;主轴、侧轴要结合 flex-direction 看,不要固定认为主轴一定横着。
四、flex-basis、flex-grow、flex-shrink 与 flex
为什么需要:控制项目在主轴上的长度以及如何瓜分富余空间、如何承担亏空。
怎么想:flex-basis 是项目在主轴上的长度,默认 auto,一旦设置就优先于对应方向的宽或高;flex-grow 默认 0,有富余空间才扩展;flex-shrink 默认 1,主轴空间不够且不换行时才收缩。
怎么做:扩展案例中容器 1000,项目原长 100、200、300,富余 400;flex-grow 为 1、6、3 时,按比例分 40、240、120,最终 140、440、420。收缩案例容器 500,亏空 100,flex-shrink 为 5、3、2 时,分母是 100×5+200×3+300×2=1700,各扣 100×5/17、100×6/17、100×6/17。
css
.item1 { flex-grow: 1; }
.item2 { flex-grow: 6; }
.item3 { flex-grow: 3; }
/* 常见简写 */
.a { flex: 1; } /* 1 1 0%,常用于瓜分容器 */
.b { flex: 0 0 auto; } /* 不伸不缩 */
.c { flex: 0 1 auto; } /* 默认:能缩不能伸 */易错点:扩展只看 flex-grow,不看原主轴长度;收缩既要看 flex-shrink,也要看原主轴长度;flex-grow:0 分不到,flex-shrink:0 不收缩;flex:1 的 basis 是 0%,不是原宽高。
五、布局特点与最小内容宽度
为什么需要:理解 flex:1 为什么能把容器瓜分干净。
怎么想:三个项目 basis 都为 0 时,富余空间就是整个容器,再按 flex-grow 均分。容器不设宽时,它仍是块级伸缩容器,宽度跟父元素一样,不会“被内容撑开”。
怎么做:用 flex:1 让多个项目平均瓜分容器。
易错点:收缩有底线,内边距不会消失,不可断开的单词会形成最小内容宽度,继续压缩会出现滚动条,不会把内容压没。
六、order 与 align-self
为什么需要:单独调整项目视觉顺序和侧轴对齐。
怎么想:order 默认 0,值越大越靠后,可为负;align-self 默认 auto,表示跟随容器 align-items,其他值同 align-items。
怎么做:
css
.item2 { order: 1; }
.item3 { order: -1; }
.item2 { align-self: flex-end; }易错点:order 只改视觉顺序,不改 DOM 顺序;align-self 设在伸缩项目上,不是容器上。
作业目标:用 Flex 完成等分布局与页面布局
本节作业有两个目标:一是做等分布局,二是用 Flex 完成一个页面布局。转写稿里反复强调:Flex 的核心不是“横着怎么写、竖着怎么写”,而是先分清伸缩容器和伸缩项目,再看主轴、侧轴。传统浮动和块级布局里,横向、纵向差别很大;Flex 里四个方向更平等,所以居中、等分、排序都可以围绕容器和项目来设置。
为什么需要:作业要把零散属性落到页面上,不能只背 justify-content、align-items。
怎么想:先让父元素 display:flex,子元素才成为伸缩项目;再决定主轴对齐、侧轴对齐、是否等分。
怎么做:下面按“等分布局”和“页面居中布局”分别写。
易错点:属性设错对象就失效——容器属性写给容器,项目属性写给项目。
等分布局:用 flex:1 让子项平均瓜分容器
为什么需要:多个卡片、多个模块要等宽排列时,手算宽度很麻烦,还要处理间距。
怎么想:转写稿里说,扩展的前提是容器在主轴上有富余空间,并且项目的扩展比率不能是 0。flex:1 常见理解为扩展比率 1、收缩比率 1、主轴长度 0;三个项目主轴长度都为 0 时,容器剩余空间全部成为富余空间,再按 flex-grow 平均分,所以看起来就是等分。
怎么做:
html
<div class="wrapper">
<div class="item01">item01</div>
<div class="item02">item02</div>
<div class="item03">item03</div>
</div>css
.wrapper {
display: flex;
width: 1000px;
}
.item01,
.item02,
.item03 {
padding: 10px;
background: #999;
color: #fff;
flex: 1; /* 等分布局:让三项平均瓜分主轴空间 */
}调试时先看父容器宽度,再看子项是否还保留了原来的 width。转写稿明确说:一旦设置了 flex-basis,主轴长度就按它来,和主轴方向对应的 width 或 height 就不再生效;flex:1 里 basis 为 0,所以原来的 100、200、300 不再决定最终等分结果。
易错点:flex:1 不是“宽度写 1”;等分时不要再纠结原来的 width。有 padding 时内边距会保留,页面变窄时项目会收缩,但不会无限压没内容,最小宽度受内容影响。
Flex 布局页面:让 book 模块在视口中居中
为什么需要:作业页面常要求一个模块在页面中水平、垂直居中,且不写死高度。
怎么想:转写稿给了两种方案。方案一是把 body 变成伸缩容器,book 成为伸缩项目,再用主轴、侧轴对齐;方案二更短:body 设 display:flex,给 book 设 margin:auto。因为 Flex 里四个方向平等,margin:auto 不只在左右生效,上下也能生效。
怎么做:
html
<div class="book">book</div>css
html,
body {
height: 100%;
}
body {
margin: 0;
display: flex;
justify-content: center; /* 主轴居中 */
align-items: center; /* 侧轴居中 */
}
.book {
width: 400px;
padding: 20px;
background: #333;
color: #fff;
}也可把 body 里的对齐换成:
css
body {
margin: 0;
display: flex;
}
.book {
margin: auto;
}易错点:转写稿调试时先发现 body 没高度,所以 html,body 都要 height:100%;又出现竖向滚动条,是因为 body 自带外边距,要 margin:0。如果侧轴不设固定高度,项目默认会被拉伸;不想拉伸又要居中,就用 align-items:center。只有一个项目时不要想 align-content,它主要针对换行后的多行。另:容器没有子元素但有文字时,主轴/侧轴对齐也能作用于文字,但一般文字居中用 text-align、line-height 更直接。
页面细节:order 排序与 align-self 单独对齐
为什么需要:页面模块顺序可能要调整,某个卡片也可能要单独在侧轴上对齐。
怎么想:order 写在伸缩项目上,默认 0,数值越大越靠后,可为负值;align-self 也写在项目上,默认 auto,表示跟随容器的 align-items,其他值同 align-items。
怎么做:
css
.item02 {
order: 1; /* 比默认 0 大,往后排 */
}
.item03 {
order: -1; /* 负数更靠前 */
}
.item02 {
align-self: flex-end; /* 单独在侧轴靠下 */
}易错点:order 和 align-self 都写给伸缩项目,不要写给容器;align-self:auto 不是“无对齐”,而是跟随容器设置。
作业验收清单
- 父容器是否设置了
display:flex。 - 等分布局是否给子项设置了
flex:1,并检查原width是否干扰。 - 页面居中是否检查了
html,body{height:100%}和body{margin:0}。 - 侧轴居中是否用
align-items:center,没有误用align-content。 order、align-self是否写在伸缩项目上。
课堂画面






代码示例
示例 1:Flex 实现元素居中(两种方案)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Flex 实现元素居中(两种方案)</title>
<style>
/* html 参照视口,body 参照 html,这样 body 才有高度 */
html, body { height: 100%; }
/* body 自带 8px 外边距,不清零会出现竖向滚动条 */
body { margin: 0; font: 16px/1.5 sans-serif; }
.stage {
height: 50%;
display: flex; /* 变成伸缩容器,.book 才是伸缩项目 */
background: #333;
}
.stage-2 { background: #555; }
.book {
width: 400px;
padding: 20px; /* 高度不设,由内容撑开 */
color: #fff;
background: #09f;
}
/* 方案一:主侧轴对齐方式 */
.stage-1 { justify-content: center; align-items: center; }
/* 方案二:伸缩项目 margin: auto */
.stage-2 .book { margin: auto; }
</style>
</head>
<body>
<div class="stage stage-1">
<div class="book">方案一:justify-content:center + align-items:center</div>
</div>
<div class="stage stage-2">
<div class="book">方案二:margin:auto(上下左右外边距都是 auto)</div>
</div>
</body>
</html>关键行与易错点
html, body { height: 100% }:body 默认没有高度,不写这句align-items: center就没有可居中的空间,这是最容易漏的一步。body { margin: 0 }:body 自带 8px 外边距,不清零会出现竖向滚动条。display: flex必须写在父元素(伸缩容器)上;只给.book写对齐属性无效。- 方案一:
justify-content管主轴(默认横向),align-items管侧轴(纵向)。只有一个项目,不存在换行,align-content在这里完全没用。 - 方案二:给伸缩项目写
margin: auto,四个方向都是 auto。普通块级元素margin: auto只能横向居中,而 Flex 里主轴和侧轴是平等的,所以上下也生效,代码还更短。 - 补充:容器里没有子元素、只有文字时,
justify-content/align-items也能直接作用于文字。
示例 2:扩展比率 flex-grow 与收缩比率 flex-shrink
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>flex-grow 扩展 / flex-shrink 收缩</title>
<style>
body { margin: 0; font: 14px/1.5 sans-serif; background: #eee; }
.wrapper {
display: flex; /* 伸缩容器,主轴横向 */
width: 1000px; /* 容器主轴长度 1000px */
margin-bottom: 20px;
background: #ccc;
}
/* border-box 让 padding 含在宽度里,主轴长度就是 100/200/300 */
.item {
padding: 10px;
box-sizing: border-box;
color: #fff;
background: #09f;
border: 1px solid #fff;
}
.item01 { width: 100px; }
.item02 { width: 200px; }
.item03 { width: 300px; }
/* 扩展:富余 1000 - (100+200+300) = 400,按 1:6:3 瓜分 */
.grow .item01 { flex-grow: 1; } /* 400 × 1/10 = 40 → 140px */
.grow .item02 { flex-grow: 6; } /* 400 × 6/10 = 240 → 440px */
.grow .item03 { flex-grow: 3; } /* 400 × 3/10 = 120 → 420px */
/* 收缩:容器只有 500,亏空 100,shrink 5:3:2 且要乘原主轴长度 */
.shrink { width: 500px; }
.shrink .item01 { flex-shrink: 5; }
.shrink .item02 { flex-shrink: 3; }
.shrink .item03 { flex-shrink: 2; }
</style>
</head>
<body>
<div class="wrapper grow">
<div class="item item01">item01</div>
<div class="item item02">item02</div>
<div class="item item03">item03</div>
</div>
<div class="wrapper shrink">
<div class="item item01">item01</div>
<div class="item item02">item02</div>
<div class="item item03">item03</div>
</div>
</body>
</html>关键行与易错点
flex-grow默认值是 0:能屈不能伸,不写就永远不扩展。- 扩展只看比率,不看原来的主轴长度:富余 400 按 1:6:3 分成 40 / 240 / 120。
flex-shrink默认值是 1:默认就会收缩。收缩的前提是:容器主轴长度不够、不能换行、shrink 不为 0。- 收缩要同时看收缩比率和原主轴长度:分母 = 100×5 + 200×3 + 300×2 = 1700,各自承担 100 的 500/1700、600/1700、600/1700,所以原来长的收得多。
flex-basis优先级高于主轴方向对应的width/height,默认auto(等于没设,仍按 width/height)。- 易错点:给收缩容器加
flex-wrap: wrap就看不到收缩了,变成换行;padding永远不参与收缩;项目受内容最小宽度限制,不能无限压缩,压到极限会出现滚动条。
示例 3:等分布局 + order 排序 + align-self
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>等分布局 / order 排序 / align-self</title>
<style>
body { margin: 0; font: 14px/1.5 sans-serif; background: #eee; }
.wrapper {
display: flex;
width: 1000px;
height: 300px; /* 侧轴要有高度,align-items / align-self 才看得出来 */
margin-bottom: 20px;
background: #ccc;
}
.item {
padding: 10px;
box-sizing: border-box;
color: #fff;
background: #09f;
border: 1px solid #fff;
}
/* 1. 等分布局:flex: 1 1 0% = grow 1 / shrink 1 / basis 0% */
.equal .item { flex: 1 1 0%; } /* 三个项目平分 1000px */
/* 2. 排序:order 默认 0,数值越小越靠前,可为负 */
.order .item02 { order: 1; } /* 排到最后 */
.order .item03 { order: -1; } /* 排到最前 */
/* 3. 单独设置侧轴对齐 */
.align { align-items: center; } /* 容器统一:全部侧轴居中 */
.align .item02 { align-self: flex-end; } /* 只有它单独跑到底部 */
</style>
</head>
<body>
<div class="wrapper equal">
<div class="item">item01</div>
<div class="item">item02</div>
<div class="item">item03</div>
</div>
<div class="wrapper order">
<div class="item item01">item01</div>
<div class="item item02">item02</div>
<div class="item item03">item03</div>
</div>
<div class="wrapper align">
<div class="item item01">item01</div>
<div class="item item02">item02</div>
<div class="item item03">item03</div>
</div>
</body>
</html>关键行与易错点
flex: 1 1 0%是复合属性简写:扩展 1、收缩 1、主轴长度 0%。因为flex-basis: 0%覆盖了width,三个项目起点都是 0,于是把容器等分——这就是作业“等分布局”的标准写法。flex-basis一旦设置,主轴方向上的width/height就不起作用了,所以等分布局不用再管原来写了多宽。order写在伸缩项目上,默认 0,值越小越靠前、可为负;它只改视觉顺序,不改 DOM 顺序,别指望它影响 Tab 键顺序。align-self也写在伸缩项目上,默认auto表示跟随容器的align-items,其他取值与align-items相同(flex-start/flex-end/center/stretch等)。- 易错点:把
order、align-self误写到容器上;容器没有设高度时,align-self看不出任何效果。
常见错误
全屏居中失效,页面高度不够
现象:给body设display:flex后,元素仍无法在视口垂直居中。
原因:html、body没有可用高度,伸缩容器高度由内容撑开。
修法:先设html, body { height:100%; },再让body成为伸缩容器。出现多余竖向滚动条
现象:设置html, body { height:100%; }后页面出现滚动条。
原因:body默认外边距仍在,总高度超出视口。
修法:重置body { margin:0; },再检查是否有额外 margin/padding。对齐属性写错对象
现象:写了justify-content:center或align-items:center,项目没反应。
原因:把容器属性写到了伸缩项目上。
修法:justify-content、align-items、align-content、flex-wrap、flex-direction设在伸缩容器;order、align-self、flex-*设在伸缩项目。主轴、侧轴方向判断反了
现象:想水平居中却用了align-items,想垂直居中却用了justify-content,结果不符合预期。
原因:仍按“横向/纵向”理解,没有按当前主轴、侧轴判断。
修法:先看flex-direction确定主轴,再用justify-content控主轴、align-items控侧轴。设置
flex-basis后还纠结width/height
现象:项目同时写了width和flex-basis,最终宽度不是width。
原因:flex-basis在主轴长度上优先级更高。
修法:明确以flex-basis为准;不需要时保留默认auto,用主轴对应的宽或高控制。误以为
flex-grow默认可扩展,或换行后还会收缩
现象:容器有剩余空间但项目不放大;容器空间不足时却直接换行、不收缩。
原因:flex-grow默认0;发生换行后不再按单行收缩逻辑处理。
修法:需要分配剩余空间时显式设flex-grow;需要观察收缩时确保flex-wrap:nowrap。
练习
- 做一个全屏居中卡片:卡片宽度自适应内容、无固定高度,要求水平和垂直都居中,并消除页面默认滚动条。
- 用 Flex 完成三列等分布局,再改成三列比例为
1:3:6,分别用flex-grow和简写方式实现。 - 容器主轴宽度
500px,三个项目原主轴长度为100px / 200px / 300px,收缩比例分别为5 / 3 / 2。写出最终宽度计算过程,并说明为什么不是简单按5:3:2扣减。 - 做一个商品卡片列表:容器宽度变化时自动换行,要求区分
align-items与align-content的作用,并说明多行时该用哪个控制行间对齐。 - 给定三个伸缩项目,使用
order调整显示顺序,并只用align-self让其中一个项目单独靠侧轴末端对齐。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 伸缩盒布局实现元素居中 | 06:32 |
| 2 | 主侧轴对齐方式作用于文字 | 02:24 |
| 3 | 设置给伸缩容器的相关CSS属性总结 | 04:00 |
| 4 | 伸缩项目的扩展比率 | 18:12 |
| 5 | 伸缩项目的收缩比率 | 12:06 |
| 6 | 伸缩项目布局特点 | 17:18 |
| 7 | 伸缩项目排序和单独设置侧轴对齐方式 | 04:38 |
小结
- 先判断“谁是容器、谁是项目”,再决定属性写给谁,能避免大部分 Flex 失效问题。
- 居中问题优先检查容器高度、
body默认 margin、主轴侧轴方向这三件事。 - 主轴方向一变,
justify-content和align-items的视觉效果就跟着变,不要死记“横竖”。 flex-basis管主轴长度,且优先级高于主轴对应的width/height;默认auto时不要多设。flex-grow分配剩余空间只看扩展比例;flex-shrink收缩要同时看收缩比例和原主轴长度。- 换行会改变收缩与对齐逻辑:要收缩先保证不换行,多行对齐要想到
align-content。 order、align-self只作用于单个伸缩项目,适合做局部排序和局部对齐。- 调试 Flex 时先看容器实际尺寸、是否换行、主轴方向,再看项目尺寸和 flex 相关属性。