首页 CSSDAY4 Flexbox And Grid
文章
取消

CSSDAY4 Flexbox And Grid

开始根据林想的Web工坊大佬的建议路线学习CSS。

本文涉及内容会如下:

CSS flexible box layout - CSS | MDN

CSS grid layout - CSS | MDN

flex是内容驱动排列,而grid则是布局驱动排列。


📊 本节知识点重要度速览

display: flex / 双轴概念 / flex: 1 / align-items / justify-content 🔴 每天必写;

flex-direction / flex-wrap / flex-grow / flex-shrink / align-self 🟡 常用;

flex-flow 简写 / row-reverse column-reverse / 初始值细节 🟢 知道就行;

书写模式(writing modes)理论 ⚪ 了解即可。

The two axes of flexbox(Flexbox 的双轴模型)

Flexbox 被称为一维(one-dimensional)布局模型,它一次只在一个维度上进行布局,要么是一行(row),要么是一列(column)。这与 CSS Grid 的二维模型形成了核心区别:Grid 同时控制列和行,而 Flexbox 一次只处理一个方向。

这个”一维”是理解 Flexbox 所有行为的总钥匙。所有属性都是围绕”主轴”和”交叉轴”两个概念展开的,主轴决定元素往哪个方向排列,交叉轴决定另一个方向上如何对齐。

使用 Flexbox 时,需要始终在两个轴之间切换思维。主轴(main axis)由 flex-direction 属性定义,交叉轴(cross axis)垂直于主轴。

The main axis(主轴)

flex-direction 有四个可能的值:

  • row(默认):主轴沿行方向,从左到右(inline direction)
  • row-reverse:主轴沿行方向,但从右到左
  • column:主轴沿列方向,从上到下(block direction)
  • column-reverse:主轴沿列方向,但从下到上

选择 rowrow-reverse,主轴跑 inline 方向(文字书写的水平方向);选择 columncolumn-reverse,主轴跑 block 方向(段落堆叠的垂直方向)。

The cross axis(交叉轴)

交叉轴永远垂直于主轴。所以:

  • 如果主轴是 row/row-reverse → 交叉轴沿列方向(垂直)
  • 如果主轴是 column/column-reverse → 交叉轴沿行方向(水平)

可以这样记:主轴 = 排列方向,交叉轴 = 对齐方向。 主轴决定行或列内元素从左到右排列,谁在第一个、谁在第二个、间距怎么分(justify-content);交叉轴决定这一行/列里,若干个元素在垂直方向上怎么对齐,是全部贴顶(flex-start)、全部居中(center)、全部拉伸等高(stretch)、还是全部贴底(flex-end)。

Start and end lines(起止线:Flexbox 不假设书写方向)

Flexbox 的一个重要设计理念是不假设文档的书写方向。它不会默认”文字从左上方开始、从左往右排列、新行逐行往下”,而是支持所有书写模式(writing modes),与逻辑属性(logical properties)体系保持一致。

因此,Flexbox 用 startend 代替 left 和 right:

  • 如果 flex-direction: row 且在英语环境下 → 主轴 start = 左,end = 右
  • 如果 flex-direction: row 且在阿拉伯语环境下 → 主轴 start = 右,end = 左
  • 两种情况下,交叉轴的 start 都在顶部、end 都在底部(因为两种语言都是水平书写模式)

习惯用 start/end 而非 left/right 思考,不仅对 Flexbox 有用,对 CSS Grid 也是一样的,两者共享这套逻辑坐标系。

The flex container(Flex 容器与初始值)

将一个元素设为 display: flex,它就变成了 flex container,其直接子元素会立即变成 flex items。也可以用 inline-flex 创建行内级别的 flex 容器。

这里有一个值得停留的点:display: flex 创建的是全新的 flex formatting context,不是 BFC。上一篇文章我们提到 Flexbox 和 Grid 创建的是全新的格式化上下文,这正是 Flexbox “摆脱了 BFC 补丁链”的技术实现。在 flex 容器内部,float 会失效、margin 不会折叠、不需要 clear,BFC 那条线的所有历史问题,在这里全部清零。

初始值(Initial values)

一个刚创建的 flex 容器,子元素会按以下默认行为排列:

  1. 沿行方向排列flex-direction 默认值为 row
  2. 从主轴 start 边缘开始
  3. 主轴上不伸长但可收缩flex-grow: 0(不伸长),flex-shrink: 1(可收缩)
  4. 交叉轴上拉伸填满align-items 默认值为 stretch,高度不同的子元素会被拉成最高元素的高度
  5. flex-basis: auto,元素的初始大小取 width/height 值,若也为 auto 则取内容大小
  6. 不换行flex-wrap 默认值为 nowrap,子元素总宽度超过容器时直接溢出

综合效果就是:所有子元素在一行内排列,各自取内容大小,高度不同的会被拉成对齐,数量太多就直接溢出。这解释了为什么第一次写 display: flex 时,元素会自动排成一行但不会换行。

1
2
3
4
5
6
7
.box {
  display: flex;
  /* 等价于以下默认值都已生效:
     flex-direction: row;
     flex-wrap: nowrap;
     align-items: stretch; */
}

Changing flex-direction(改变主轴方向)

通过 flex-direction 可以切换主轴的排列方向:

1
2
3
4
5
6
.box {
  display: flex;
  flex-direction: row-reverse; /* 仍然沿行方向,但从右到左 */
}

/* 其他可选值:row(默认)、column、column-reverse */

row-reverse 保持沿行排列,但 start 和 end 对调。column 让主轴切换到垂直方向,子元素从上到下堆叠。column-reverse 则是从下往上。

Multi-line flex containers with flex-wrap(多行 Flex 容器与换行)

虽然 Flexbox 是一维模型,但flex items 依然可以换行。不过这里有一个重要认知:每一行就是一个独立的 flex 容器。 任何空间分配都在每行内部独立计算,行与行之间互不参考。

1
2
3
4
5
6
7
8
9
.box {
  display: flex;
  width: 500px;
  flex-wrap: wrap;  /* 允许换行 */
}

.box > * {
  width: 200px;
}

三个 200px 宽的 items 在一个 500px 宽的容器里:前两个刚好放下(400px),第三个被迫换到下一行。每一行内部的空间分配都是独立的。

如果设 flex-wrap: nowrap(初始值),三个 items 会尝试挤在一行内,由于 flex-shrink: 1,它们会收缩。如果收缩还放不下,就会溢出容器。

nowrap 下的收缩行为是新手最常见的困惑:明明没设 width: 200px,为什么元素还是会被挤小?答案就是 flex-shrink 的默认值为 1。

但 flex-shrink 往往不是直接生效,它有一个隐藏的限制,即min-width。flex item 的 min-width 默认值是 auto,含义是”不能小于内容本身的最小尺寸”。

flex-shrink 设了等于白设会两种情况:

  1. 替换元素(img、video、iframe):固有宽度就是 min-width 的底,一张 800px 的图,flex-shrink: 999 也缩不动它。解法是给 img 加 max-width: 100%,让它自适应容器。

  2. 连续长单词或长数字:浏览器不会在单词中间断行,这个单词有多长,flex item 就至少有多宽,缩到这个宽度就停。解法是设 min-width: 0 强制取消内容下限,或配合 word-break: break-all 允许任意断行。

所以默认的 flex-shrink: 1 只是表达了内容元素能够被压缩的态度,实际能不能缩动,取决于内容的 min-width 的规定。

The flex-flow shorthand(flex-flow 简写)

flex-flowflex-directionflex-wrap 的组合简写:

1
2
3
4
.box {
  display: flex;
  flex-flow: row wrap;  /* 第一个值:flex-direction,第二个值:flex-wrap */
}

Properties applied to flex items(作用于 Flex Items 的三个核心属性)

在 Flexbox 中,控制每个子元素在主轴上如何分配空间,靠三个属性:

  • flex-grow:有多少剩余空间时,这个 item 能分到多少
  • flex-shrink:空间不够时,这个 item 要多快收缩
  • flex-basis:这个 item 在分配/收缩之前的初始大小

这三个属性都作用在主轴方向。理解它们之前,需要先理解一个关键概念,可用空间(available space)

Flexbox 的空间计算逻辑是:先算容器有多宽,再算所有 items 的 flex-basis 加起来占多少宽,差值就是”可用空间”(可正可负)。然后根据 flex-grow 或 flex-shrink 的比例去分配这个差值。改变这三个属性的值,本质上就是在改变”可用空间怎么分”。

举个例子:三个 100px 宽的 items 放在 500px 宽的容器里 → 占用 300px,剩余 200px 可用空间。如果什么都不设,这 200px 就会留在最后那个 item 的后面。

flex-basis(初始尺寸)

flex-basis 决定了 item 在分配空间之前的大小。默认值为 auto,浏览器会先看元素有没有显式的 width/height,有就用它;没有就用内容的自然尺寸。这就是为什么单纯设 display: flex 后,每个 item 只占内容所需的宽度,因为 flex-basis: auto,没设 width,就取内容大小。

flex-grow(伸长比例)

flex-grow 控制 item 如何吃掉可用空间。默认值为 0(不吃)。设为正整数后:

  • 所有 item 的 flex-grow 之和 = 总份数
  • 每个 item 分到的额外空间 = 可用空间 × (该 item 的 flex-grow / 总份数)
1
2
3
4
5
6
/* 三个 items 均分 200px 可用空间,各得 66.67px */
.one, .two, .three { flex-grow: 1; }

/* one 分到 100px(2/4),其余各分到 50px(1/4) */
.one { flex-grow: 2; }
.two, .three { flex-grow: 1; }

flex-grow 的值是比例,不是像素值。三个 items 都设 flex-grow: 1 和都设 flex-grow: 100,效果完全一样,因为比例相同。

flex-shrink(收缩比例)

flex-shrink 控制空间不够时,item 如何收缩。默认值为 1。

  • 值越大,收缩得越(比兄弟们更快变小)
  • item 最小可以缩到 min-content 大小(内容不可再分的最小宽度)

flex-shrink 的值也是比例。以容器 600px、三个 item 各 300px 为例:

1
2
3
4
5
6
7
8
9
/* 三个 items 均分 300px 溢出空间,各缩 100px */
.one, .two, .three { flex-shrink: 1; }
/* 结果:各从 300px 变成 200px */

/* one 缩 150px(3/6),two 缩 100px(2/6),three 缩 50px(1/6) */
.one { flex-shrink: 3; }
.two { flex-shrink: 2; }
.three { flex-shrink: 1; }
/* 结果:one→150px, two→200px, three→250px */

flex-shrink 的行为比 flex-grow 看起来更不一致,因为收缩过程要受 min-content 下限的影响,一个已经缩到内容最小宽度的 item 不能再缩,导致的收缩效果会转移到其他 item 身上。MDN 建议读到进阶文章再深入理解这一块算法。

The flex shorthand(flex 简写)

实际开发中几乎不会单独使用 flex-growflex-shrinkflex-basis,而是统一用 flex 简写:

1
2
/* flex: grow shrink basis */
.item { flex: 1 1 auto; }  /* 可伸长、可收缩、初始尺寸为 auto */

三个值的顺序:flex-growflex-shrinkflex-basis

还有一些预设值覆盖了大多数使用场景:

简写值等价于含义
flex: initialflex: 0 1 auto不伸长,可收缩,取内容/显式尺寸
flex: autoflex: 1 1 auto可伸长可收缩,取内容/显式尺寸
flex: noneflex: 0 0 auto完全僵硬,不能伸长不能收缩
flex: <number>flex: <number> 1 0最常用的 flex: 1 就是这个,basis 为 0

flex: 1 会在无数教程里看到的写法。它等价于 flex: 1 1 0,注意这里 flex-basis: 0,意味着分配空间时可以完全忽略内容尺寸。这就是为什么 flex: 1 能让子元素”均分容器宽度”,而 flex: auto(basis: auto)会让子元素先按内容占位再分余量。两者结果不同,根源就在 flex-basis 的差异。

Alignment, justification and distribution of free space between items(对齐、两端对齐与空间分配)

Flexbox 最强大的能力不是排列方向,而是对齐和对剩余空间的自动分配。当一组元素排在一行/一列里,容器还有多余空间时,怎么把这些空间”摆合理”,这就是 alignment 属性干的事。

align-items(交叉轴对齐)

align-items 控制所有 flex items 在交叉轴上的对齐方式:

  • stretch(默认):拉伸到容器交叉轴高度
  • flex-start:靠近交叉轴的 start 边缘
  • flex-end:靠近交叉轴的 end 边缘
  • center:交叉轴居中
  • baseline:按文字基线对齐

justify-content(主轴对齐/两端对齐)

justify-content 控制 flex items 在主轴上的分布方式,在有剩余空间时发挥作用:

  • flex-start(默认):items 靠主轴 start 边缘
  • flex-end:items 靠主轴 end 边缘
  • center:items 居中
  • space-between:首尾贴边,中间均分间隙
  • space-around:每个 item 两侧间隙相等(首尾 item 到容器边缘 = 间距的一半)
  • space-evenly:所有间隙完全相等(包括首尾到容器边缘)

space-between 是最常用的”两端对齐”,导航栏 logo 在最左、菜单在最右,就靠它。space-aroundspace-evenly 的区别很微妙:前者是”每个 item 周围包一圈等宽空隙”(item 间距是首尾空隙的两倍),后者是”所有空隙宽度完全相同”。

虽然都是改变items的行为,但为什么justify-content的命名里却是content呢,这是因为命名是按 Grid 的四象限来设计的,Flexbox 只是继承了这套命名里的三个(justify-contentalign-itemsalign-content),justify-items 在 Flexbox 里被闲置了。

在 Grid 中,四个功能就非常符合自己的命名了:

1
2
3
4
5
justify-content: 所有列作为一个整体,在容器里靠左/居中/靠右
justify-items:    每个格子里的 item,在自己格子里靠左/居中/靠右

align-content:    所有行作为一个整体,在容器里靠上/居中/靠下
align-items:      每个格子里的 item,在自己格子里靠上/居中/靠下

align-self(单个 item 覆盖交叉轴对齐)

可以用 align-self 单独控制某个 flex item 在交叉轴上的对齐方式,覆盖容器的 align-items 设置。

1
2
3
4
5
6
7
.box {
  display: flex;
  align-items: center;  /* 其他 items 居中 */
}
.special {
  align-self: flex-start;  /* 只有这个贴顶 */
}

小结:从 BFC 到 Flexbox 的思维转变

上一篇文章里我们说过,Flexbox 创建的是全新的 flex formatting context,BFC 的历史补丁链(float → clear → overflow: hidden → flow-root)在这里全部清零。

但 Flexbox 带给开发者的不只是”不用再打补丁”,而是一种思维方式的转变

  • BFC 思维:元素按照文档流自然堆叠,要用各种 hack 让它看起来像”布局”
  • Flexbox 思维:定义一个容器,声明”主轴走行还是列”,剩下的由 align-itemsjustify-content 自动搞定

核心要记住的只有一张表:主轴 = 排列方向(flex-direction + justify-content),交叉轴 = 对齐方向(align-items + align-self。所有 Flexbox 属性都落在这两条轴上,理解了这一对轴,Flexbox 就不再是一堆散乱的属性,而是一套统一的逻辑体系。

📊 本节知识点重要度速览

fr 单位 / repeat() / gap / grid-template-columns / grid-auto-rows / 隐式网格 🔴 每天必写;

minmax() / 基于线的放置(grid-column / grid-row)/ grid-template-areas 🟡 常用;

嵌套 Grid / z-index 层叠 🟢 知道就行;

subgrid / 四个长写属性(grid-column-start 等)⚪ 极少用到。

What is a grid?(什么是 Grid)

CSS Grid Layout 引入了二维(two-dimensional)网格系统,同时控制行和列。这是它与 Flexbox 最核心的区别:Flexbox 是一维的(每次只在一个方向上布局),Grid 是二维的(行列同时定义、元素可以跨越多个行和列)。

Grid 可以用来布局页面主体区域(header/sidebar/main/footer),也可以用来设计小型 UI 组件。Grid 规范提供以下核心能力:

  • 固定和弹性轨道尺寸:像素、百分比,以及 Grid 专属的 fr 单位
  • 精确放置元素:通过行号、命名线、或区域名称将元素放到网格的任意位置
  • 自动创建额外轨道:内容超出显式定义的网格时,自动生成新的行或列
  • 对齐控制:控制元素在网格区域内的对齐方式,以及整个网格在容器内的对齐
  • 元素重叠控制:多个元素可以放入同一个网格单元格,通过 z-index 控制层叠

如果把 Flexbox 看作”沿着一条线排列”,Grid 就是”在一张纸上画格子”。这张纸的行和列同时存在,可以把元素放到任何一个格子里,也可以让它跨多行多列。

Grid container(Grid 容器)

和 Flexbox 一样,Grid 的起点是容器

1
2
3
4
.wrapper {
  display: grid;
}
/* 或 inline-grid 创建行内级别的 grid 容器 */

设了 display: grid 之后,所有直接子元素变为 grid items。在浏览器里可能看不到任何变化,因为 Grid 默认创建的是单列网格,所有 item 依然从上到下排列。打开 DevTools 的 Grid 检查器可以看到网格线的叠加层。

display: grid 创建的是全新的 grid formatting context,与 Flexbox 一样,在 Grid 容器内部,float 失效、margin 不折叠、不需要 clear。BFC 的补丁链在这里同样彻底退场。

Grid tracks(网格轨道)

grid-template-columnsgrid-template-rows 定义网格的轨道(track),也就是列和行。轨道是两条相邻网格线之间的空间。

1
2
3
4
5
.wrapper {
  display: grid;
  grid-template-columns: 200px 200px 200px;
  /* 三列,每列 200px */
}

The fr unit(fr 单位)

Grid 引入了专属的长度单位 fr(fraction,份数),代表可用空间的一个比例份数

1
2
3
4
5
6
7
8
.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;  /* 三等分 */
}

.wrapper {
  grid-template-columns: 2fr 1fr 1fr;  /* 第一列占一半,后两列各 1/4 */
}

fr 的计算逻辑:先减掉所有固定尺寸(像素、百分比等),剩余空间按 fr 比例分配。

1
2
3
4
.wrapper {
  grid-template-columns: 500px 1fr 2fr;
  /* 500px 固定 → 剩余空间按 1:2 分配给第二列和第三列 */
}

fr 是 Grid 的灵魂单位。它让”自适应列宽”从 Flexbox 里需要手动算百分比或 flex-grow 的间接操作,变成了直接声明比例。1fr 2fr 就是”第一列占 1/3,第二列占 2/3”,直觉、直接、不用算。

repeat() notation(repeat 写法)

重复轨道可以用 repeat() 简化:

1
2
3
4
5
6
7
8
9
10
grid-template-columns: 1fr 1fr 1fr;
/* 等价于 */
grid-template-columns: repeat(3, 1fr);

/* 也可以和固定尺寸混合 */
grid-template-columns: 20px repeat(6, 1fr) 20px;

/* 甚至可以重复一段模式 */
grid-template-columns: repeat(5, 1fr 2fr);
/* 生成 10 列:1fr, 2fr, 1fr, 2fr, ... */

Implicit and explicit grids(隐式网格与显式网格)

这是 Grid 最独特的概念之一。当用 grid-template-columns 定义了 3 列,但子元素有 8 个时,Grid 会自动创建额外的行来容纳内容:

  • 显式网格(explicit grid):由 grid-template-columns / grid-template-rows 显式定义的行列
  • 隐式网格(implicit grid):内容超出显式网格时,自动扩展出来的行或列

隐式轨道默认 auto 大小,既受内容影响,也受可用空间影响。可以用 grid-auto-rows / grid-auto-columns 控制隐式轨道的大小:

1
2
3
4
5
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px;  /* 隐式行高 200px */
}

隐式网格是 Grid 设计最精妙的地方,不需要知道有多少行,只管定义列的规则,Grid 自己搞定内容溢出的部分。这和 Flexbox 的 flex-wrap 有点像,但 Grid 可以精确控制”溢出出来的新行长什么样”。

minmax()(最小最大约束)

当希望行”至少 100px 高,但如果内容更多就自动撑开”时:

1
2
3
4
5
6
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(100px, auto);
  /* 行高:最小 100px,最大 auto(撑开到内容所需) */
}

minmax() 接收两个参数:下限和上限。auto 作为上限时,轨道会增长到容纳内容的最大尺寸(max-content),同时还会和其他轨道共享容器内的剩余空间。

很明显minmax() 会是更常用的方式,具有一个基础的高度,但内容更多时也不会被截断。写死高度一般只在图片网格、仪表盘卡片这类内容高度可控的场景用。

Grid lines(网格线)

定义 Grid 时,我们定义的是轨道(tracks),不是线(lines)。但 Grid 会自动生成带编号的线,一个 3 列 2 行的网格有 4 条列线、3 条行线。

线的编号从 1 开始,方向遵循书写模式(左→右语言中 1 在左边,右→左语言中 1 在右边)。线也可以命名,用于更语义化的放置。

很容易能想到,如果我们不对网格线进行设置,items的摆放方式当然会按照fr的换分方式进行,但我们也需要清楚,fr本质划分的是轨道尺寸(track size),而我们可以让元素进行跨行的放置,也就是占用多个轨道。而我们通过对轨道线的操作可以实现这点,

Positioning items against lines(基于线的元素放置)

放置元素时,定位的是线,不是轨道:

1
2
3
4
5
6
.box1 {
  grid-column-start: 1;
  grid-column-end: 4;    /* 从列线 1 跨越到列线 4 = 占满 3 列 */
  grid-row-start: 1;
  grid-row-end: 3;       /* 从行线 1 到行线 3 = 占 2 行 */
}

注意:3 列网格有 4 条列线,所以 grid-column-end: 4 才到最右边那条线。

Line-positioning shorthands(简写)

1
2
3
4
5
6
7
8
9
10
/* 等价于上面的四个属性 */
.box1 {
  grid-column: 1 / 4;   /* start / end */
  grid-row: 1 / 3;
}

.box2 {
  grid-column: 1;       /* 只跨一列,end 可省略 */
  grid-row: 3 / 5;
}

/ 左边是 start 线号,右边是 end 线号。跨一个轨道时可以省略 end。

Grid cells(网格单元格)

网格单元格是 Grid 的最小单位,概念上类似 HTML 表格的 <td>。定义一个 Grid 后,子元素默认每个占一个单元格。

Grid areas(网格区域)

元素可以跨多行多列,形成一个网格区域(grid area)。一个关键约束:网格区域必须是矩形,不能创建 L 形区域。

Gutters(间距)

column-gaprow-gap 或简写 gap 设置列/行间距:

1
2
3
4
5
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px 1em;  /* row-gap column-gap */
}

间距空间的优先级:gap 空间fr 分配之前先扣除。也就是说,1fr 1fr 1fr + gap: 10px → 容器宽度先减去 2×10px 的总间隙,剩余空间再三等分。gap 在尺寸计算上等价于一条固定宽的轨道,但gap 里不能放东西,它是一条粗的透明线

Nesting grids(嵌套 Grid)

Grid item 可以变成 Grid container,形成嵌套网格。不过默认情况下,嵌套网格和父网格没有任何关系,线不对齐、gap 不继承。

1
2
3
4
5
6
7
8
9
10
11
12
/* 父元素:先声明 Grid,分出列 */
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);  /* 4 列 */
}

/* 子元素:在父 Grid 里跨 3 列,同时自己也是 Grid 容器 */
.box1 {
  grid-column: 1 / 4;          /* 靠父 Grid 的列线定位 */
  display: grid;               /* 自己开一套新的 Grid */
  grid-template-columns: repeat(3, 1fr);  /* 自己的子元素 3 列 */
}

Subgrid(子网格)

subgrid 让嵌套网格继承父网格的轨道定义

1
2
3
4
5
.box1 {
  grid-column: 1 / 4;
  display: grid;
  grid-template-columns: subgrid;  /* 使用父网格的列线 */
}

subgrid 是 Grid Level 2 的特性,解决的痛点是”嵌套网格的列线和父网格对不齐”。在实际项目中,如果在一个卡片网格里嵌套了另一个子卡片网格,想让它们的列宽完美对齐,就需要 subgrid。不过浏览器兼容性要留意,目前主流浏览器基本都支持了。

Layering items with z-index(用 z-index 控制层叠)

Grid 的一个独特能力是:多个元素可以放入同一个单元格,自然形成重叠。通过 z-index 可以控制谁在上谁在下,和定位元素的层叠逻辑一样。

1
2
3
4
5
6
7
8
9
10
.box1 {
  grid-column: 1 / 4;
  grid-row: 1 / 3;
  z-index: 2;  /* 在上层 */
}
.box2 {
  grid-column: 1;
  grid-row: 2 / 4;
  z-index: 1;  /* 在下层 */
}

小结:Flexbox 和 Grid 的互补

学完 Flexbox 又学 Grid,最容易产生的疑问是:”到底用哪个?”

答案不是二选一,是组合使用。

 FlexboxGrid
维度一维(行或列)二维(行列同时)
核心理念沿一个轴排列 + 对齐先画格、再放元素
内容驱动 vs 布局驱动内容决定排列(flex-basis: auto网格先定义、内容再填入
适用场景导航栏、按钮组、表单行、列表页面骨架(header/sidebar/main/footer)、卡片网格、仪表盘
关键单位flex-grow 比例fr 比例 + minmax()

一个简单判断法则:“我是不是要知道每一列有多宽、每一行有多高”,如果是,用 Grid;“我只关心元素沿一个方向怎么排列和对齐”,用 Flexbox。实际项目中,可以用 Grid 搭页面骨架,用 Flexbox 做组件内部的排列。

容器属性(写在父元素上)

FlexboxGrid作用
display: flexdisplay: grid开启布局上下文
flex-directiongrid-template-columns/rows主轴方向 / 轨道划分
flex-wrapgrid-auto-rows/columns换行 / 隐式轨道
justify-contentjustify-content整组在主轴上的位置
align-itemsalign-items整组在交叉轴上的位置
align-contentalign-content多行分布
gapgap间距

子项属性(写在子元素上)

FlexboxGrid作用
flex-grow伸长比例
flex-shrink收缩比例
flex-basis起始尺寸
align-selfalign-self自己单独的对齐
orderorder排列顺序
grid-column跨列
grid-row跨行
grid-area占区域
本文由作者按照 CC BY 4.0 进行授权