Skip to content

伸缩盒布局 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

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

课堂画面 6

代码示例 ​

示例 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 看不出任何效果。

常见错误 ​

  1. 全屏居中失效,页面高度不够
    现象:给 body 设 display:flex 后,元素仍无法在视口垂直居中。
    原因:html、body 没有可用高度,伸缩容器高度由内容撑开。
    修法:先设 html, body { height:100%; },再让 body 成为伸缩容器。

  2. 出现多余竖向滚动条
    现象:设置 html, body { height:100%; } 后页面出现滚动条。
    原因:body 默认外边距仍在,总高度超出视口。
    修法:重置 body { margin:0; },再检查是否有额外 margin/padding。

  3. 对齐属性写错对象
    现象:写了 justify-content:center 或 align-items:center,项目没反应。
    原因:把容器属性写到了伸缩项目上。
    修法:justify-content、align-items、align-content、flex-wrap、flex-direction 设在伸缩容器;order、align-self、flex-* 设在伸缩项目。

  4. 主轴、侧轴方向判断反了
    现象:想水平居中却用了 align-items,想垂直居中却用了 justify-content,结果不符合预期。
    原因:仍按“横向/纵向”理解,没有按当前主轴、侧轴判断。
    修法:先看 flex-direction 确定主轴,再用 justify-content 控主轴、align-items 控侧轴。

  5. 设置 flex-basis 后还纠结 width/height
    现象:项目同时写了 width 和 flex-basis,最终宽度不是 width。
    原因:flex-basis 在主轴长度上优先级更高。
    修法:明确以 flex-basis 为准;不需要时保留默认 auto,用主轴对应的宽或高控制。

  6. 误以为 flex-grow 默认可扩展,或换行后还会收缩
    现象:容器有剩余空间但项目不放大;容器空间不足时却直接换行、不收缩。
    原因:flex-grow 默认 0;发生换行后不再按单行收缩逻辑处理。
    修法:需要分配剩余空间时显式设 flex-grow;需要观察收缩时确保 flex-wrap:nowrap。

练习 ​

  1. 做一个全屏居中卡片:卡片宽度自适应内容、无固定高度,要求水平和垂直都居中,并消除页面默认滚动条。
  2. 用 Flex 完成三列等分布局,再改成三列比例为 1:3:6,分别用 flex-grow 和简写方式实现。
  3. 容器主轴宽度 500px,三个项目原主轴长度为 100px / 200px / 300px,收缩比例分别为 5 / 3 / 2。写出最终宽度计算过程,并说明为什么不是简单按 5:3:2 扣减。
  4. 做一个商品卡片列表:容器宽度变化时自动换行,要求区分 align-items 与 align-content 的作用,并说明多行时该用哪个控制行间对齐。
  5. 给定三个伸缩项目,使用 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

小结 ​

  1. 先判断“谁是容器、谁是项目”,再决定属性写给谁,能避免大部分 Flex 失效问题。
  2. 居中问题优先检查容器高度、body 默认 margin、主轴侧轴方向这三件事。
  3. 主轴方向一变,justify-content 和 align-items 的视觉效果就跟着变,不要死记“横竖”。
  4. flex-basis 管主轴长度,且优先级高于主轴对应的 width/height;默认 auto 时不要多设。
  5. flex-grow 分配剩余空间只看扩展比例;flex-shrink 收缩要同时看收缩比例和原主轴长度。
  6. 换行会改变收缩与对齐逻辑:要收缩先保证不换行,多行对齐要想到 align-content。
  7. order、align-self 只作用于单个伸缩项目,适合做局部排序和局部对齐。
  8. 调试 Flex 时先看容器实际尺寸、是否换行、主轴方向,再看项目尺寸和 flex 相关属性。