CSS Flexbox:弹性布局入门 · Lesson 1 of 5

第 1 课:让盒子排成一行的那行声明

本课目标:

  • 说出 display: flex 对容器及其子元素做了什么。
  • 辨认哪些元素会变成 flex item(哪些不会)。
  • 预测 flex item 默认沿主轴排成一行。

先修条件:你会写一个带 class 的 <div> 并设置一个 CSS 属性 | 下一篇 02 >>

没有 Flexbox 时,盒子只会竖着堆。为什么?

往页面上放三个 <div>,它们会竖直堆叠,每个独占一行。这是正常的块级布局,而多年以来,把它们并排放的办法只有浮动和 inline-block 这类到处漏间距 bug 的手段。如果 Flexbox 在你眼里是一堆“粘贴上去再祈祷”的属性,通常是因为没人给你讲它做的第一件事,也就是其他所有属性都依赖的那件事。这一课只讲这第一件事:一条声明,把竖着的堆变成横着的一行。掌握这一点,课程剩下的部分不过是“哪个方向、哪条轴”。

讲解

起步的全部诀窍在这里。你选定容器(包住那些盒子的元素),在它身上设置一个属性:display: flex。该容器的直接子元素随即成为 flex item1。这就是整个开关。

你这么做的那一刻,子元素不再堆叠,而是从左到右排成一行。它们现在沿着容器的主轴排列,主轴默认是水平方向1。你完全没有碰子元素,你改的是父元素,而父元素现在把它的子元素按一条 flex 行摆放。

有一个细节常常绊倒人:只有直接子元素会变成 flex item。如果 flex 容器里放着一张卡片,而卡片内部又有一个标题和一个段落,那么卡片是 flex item,但标题和段落不是。它们属于卡片,比这个容器能安排的层级深了一层2

“只往下一层”这件事是特性而不是限制,因为容器可以嵌套。给那张卡片自己也设上 display: flex,它就成了一个嵌套 flex 容器:同一时刻既是外层行的 flex item,又是自己标题和段落的 flex 容器。真实布局都是这么搭的——外层容器摆卡片,每张卡片摆自己的内容。嵌套不需要任何特殊写法,你只是在下一层再写一次 display: flex

还有一个同族的值。display: inline-flex 同样会造出一个 flex 容器,对子元素的作用完全一样;区别只在容器自己怎么待在页面里——flex 让它成为块级 flex 容器,inline-flex 让它成为行内的1。如果你的一行 item 内部排得没问题,却死活不肯和旁边的文字并排,要看的就是外层这个值。

下面的编辑器是真的。三个盒子正在堆叠。给 .row 加上那条把它变成 flex 容器的声明。

当状态点变成完成时,盒子就在主轴上了。注意你只给 .row 加了 display: flex,没有设宽度、没有浮动、没有对盒子本身做任何事。这就是整门课建立在其上的转变:你通过配置父元素来安排子元素。

完整示例(跟着做)

假设你有一个页头,里面是 logo 和导航,它们正在堆叠:

一步一步说清为什么这样有效。.bar 是容器,所以 display: flex 设在它身上。它的直接子元素是 .logo.links,正好是两个 flex item。设了 display: flex 之后,这两个 item 沿主轴排列,主轴默认水平,所以 logo 和导航在同一行上,logo 在左。你没有给任何子元素设置尺寸,是 flex 行把它们摆好的。

你来试试(填空示例)

你有一个工具栏,三个按钮应该排成一行,但它们正在堆叠。补上缺的那一行:

答案:缺的那一行是 display: flex;。三个 <button> 元素是 .toolbar 的直接子元素,所以它们变成 flex item,沿主轴排成一行。按钮本身什么都不用改。

这一行已经替你定下了什么

display: flex 不是一个行为,它一次性打开了一整套初始值,而后面每一课其实都只是在覆盖其中某一个。现在把这份清单读一遍是值得的,因为你后面会遇到的每一个“意外”,都是这些默认值在老实干活1

  • item 排成一行,因为 flex-direction 的起点是 row
  • item 从主轴的起始边开始排,而不是从中间开始。
  • item 在主轴方向上不拉伸、但可以收缩,因为 flex-grow 起点是 0flex-shrink 起点是 1
  • item 会拉伸填满交叉轴,因为 align-items 的起点是 stretch——这就是为什么三张内容不一样多的卡片,你什么都没写它们却一样高。
  • 每个 item 在主轴上的尺寸来自它自己的 width,没有 width 就来自内容,因为 flex-basis 起点是 auto
  • 所有东西都留在一行上,放不下就溢出,因为 flex-wrap 起点是 nowrap

Flexbox 是一维布局模型:它一次只沿一条轴摆放 item,要么一行要么一列,这正是它和 CSS Grid 的分界——Grid 同时控制行和列这两个维度1。当你发现自己想让 item 既在列方向对齐在行方向对齐时,那就是信号:你已经走出 Flexbox 的职责范围了。

小结 + 下节课预告

容器上的 display: flex 把它的直接子元素变成 flex item,并沿主轴摆放,主轴默认水平。你通过配置父元素来安排子元素,而 flex 只往下作用一层。下一课我们给两条轴命名,因为一旦有了两个方向,每条轴各有一个对齐属性,justify-contentalign-items 也就终于讲得通了。

Footnotes

  1. MDN: Basic concepts of flexbox — https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Basic_concepts 2 3 4 5

  2. CSS-Tricks: A Complete Guide to Flexbox — https://css-tricks.com/snippets/css/a-guide-to-flexbox/

Exercises

01

在你自己的编辑器里新建一个空白 .html 文件,写一个 <div class="row">,里面放三个子 <div>。用浏览器打开,确认三个 div 在堆叠。然后给 .row 加上 display: flex 并刷新。

第 1 级(热身)
Done criteria · checked locally
02

在你的 flex 行里嵌一张卡片:给其中一个子 div 加上自己的 <h3> 和 <p>。刷新并观察。<h3> 和 <p> 是被这条 flex 行安排的吗?

第 2 级(进阶)
Done criteria · checked locally

My note

Jot down thoughts, sticking points, things you didn't get. Written to this course's appendix only — the lesson file is never touched.