复习 CSS Flex 和 Grid 布局

还记得那些年被 CSS 布局折磨的日子吗?float: left 配合 clear: both,各种奇技淫巧只为让元素乖乖待在该待的地方。好在现代 CSS 给了我们两个布局神器:FlexGrid

如果你已经在用这两个布局方式,但偶尔还是会被轴向搞混,那这篇复习笔记正好适合你。我们会从最基础的概念开始,到实际的使用技巧,再到 Tailwind 的原子类封装,最后总结一些实战心得。

准备好了吗?复习开始!

Flex

Flex 被翻译为弹性布局,看名字就知道,主打一个 。(此处应有音效~ Duang~

一个弹性盒子里的内容我们只需要设置部分的宽度,其他没有设置的就能自如调整自己宽度,填满盒子。

最常见的需求写成代码如下:

html 复制代码
<div class="fixed-flex">
	<div class="side">侧边栏</div>
	<div class="main">主内容</div>
</div>

<style>
	.fixed-flex {
		display: flex;
	}
	.side {
		width: 200px;
		background: #ffecb3;
	}
	.main {
		flex-grow: 1;
		flex-shrink: 1;
		flex-basis: 0%;
		background: #fff9c4;
	}
</style>

.side 宽度固定 200px,对于 .main

  • 宽度不设置:flex-basis: 0%
  • 有多余空间时会膨胀:flex-grow: 1
  • 空间不足时收缩:flex-shrink: 1

以上 3 个值可以简写成一个 flex: 1,不过新手不推荐用除了 flex: 1 之外的 flex 属性,因为这个属性的语法有一点复杂

换行

有时候你确实不想只填满一行,Flex 也给你换行的选项。

html 复制代码
<div class="wrap-layout">
	<div>Akira</div>
	<div>Astro Boy</div>
	<div>Cowboy Bebop</div>
	<div>Dragon Ball Z</div>
	<div>Fullmetal Alchemist</div>
	<div>Ghost in the Shell</div>
	<div>Mobile Suit Gundam</div>
	<div>Neon Genesis Evangelion</div>
	<div>Princess Mononoke</div>
	<div>Sailor Moon</div>
</div>
<style>
	.wrap-layout {
		display: flex;
		flex-wrap: wrap;
		gap: 10px;
	}
	.wrap-layout div {
		width: auto;
		background: #c8e6c9;
		padding: 10px;
		text-align: center;
	}
</style>

默认情况下,Flex 布局只有单行,元素位置不够会被自动挤压,添加 flex-wrap: wrap; 后,就能保持其宽度自动换行。

交叉轴

Flexbox 的设计理念是一维布局,它要么是行(row),要么是列(column)。这意味着所有子元素都会沿着主轴(main axis) 排成一条线。但是换行之后就不可避免地成为二维布局,产生了交叉轴(cross axis) 的概念。

默认情况下,横着的是主轴,换行就产生了垂直于主轴的交叉轴。

与主轴有关的 CSS 属性带有 justify 前缀:

  • justify-content

与交叉轴有关的 CSS 属性带有 align 前缀:

  • align-content
  • align-items
  • align-self

align-content 控制的是多行的情况下 ,行与行之间的排布,你不用 wrap 的话这个属性是不会生效的;align-items 控制的是单行内元素的排布。

排列方向

我们可以通过 flex-direction: column; 切换主轴方向。

html 复制代码
<div class="column-layout">
	<div>上</div>
	<div>中</div>
	<div>下</div>
</div>

<style>
	.column-layout {
		display: flex;
		flex-direction: column;
		gap: 10px;
	}
</style>

十分简单!我们只需要一句 flex-direction: column; 就能把主轴从水平改为垂直,麻烦的它会给你带来一些思维负担。

上述所说的主轴、交叉轴、justify、align、换行概念都不变,只需要你把主轴换成垂直重新理解就好了,这不难,只是需要时间适应。

居中

Flex 拥有新时代最方便的居中布局的方法,justify-content: center;align-items: center;

2015 年就在干前端的老家伙们仍记得,当年还需要记各种 CSS 居中 hack,现在浏览器跟上了,大部分时间都只需要使用 Flex 就能解决问题。

正如上面所说,justify-content 是主轴元素间的分布,align-items 是交叉轴一维元素的分布,结合起来就是在 Flex 盒子内完全居中。

html 复制代码
<div class="center">
	<p>居中内容</p>
</div>
<style>
	.center {
		display: flex;
		justify-content: center;
		align-items: center;
		height: 200px;
		background: #f0f0f0;
	}
</style>

这时候有朋友就要提问了,用 align-content 从行的视角居中不可以吗?也是可以的,不过正如上面所说,必须设置 wrapalign-content 才能生效,所以得多加一行:

css 复制代码
.center {
	display: flex;
	justify-content: center;
	flex-wrap: wrap;
	align-content: center;
	height: 200px;
	background: #f0f0f0;
}

你可以在这个互动学习网站玩玩 Flex 的 wrapalignjustify 具体属性对元素布局的影响。

Bonus :Flex 父元素被撑爆了怎么办?当你设置了文字不换行之后,Flex 父元素经常会出现被撑爆的情况,这时候记得设置 overflow 属性。我觉得这里挺奇怪的,如果布局是垂直的时候,我会很容易想到设置 overflow,但是使用 Flex 之后布局变成水平了,我就老忘记设置 😂

Grid

Grid 布局就是一个画格子的游戏,一个例子让我们看看格子怎么画:

css 复制代码
.container {
	display: grid;
	grid-template-columns: 100px 200px auto;
	grid-template-rows: 50px auto 50px;
}

某种程度上 Grid 比 Flex 简单,因为基本不用切换主轴和交叉轴的概念,不容易记混。对于 Grid 我们只要知道行列怎么设置就行了。

grid-template-columns 设置 Grid 的列,100px 200px auto 的含义就是第一列 100px,第二列 200px,第三列自适应。

grid-template-rows 设置 Grid 的行,50px auto 50px 的含义就是第一行 50px,第二行自适应,第三行 50px。

还有一个十分实用的单位 fr,代表弹性比例(剩余空间的分数单位),举个例子:

css 复制代码
.container {
	display: grid;
	grid-template-columns: repeat(3, 1fr); /* 1fr 1fr 1fr */
}

这样就是把列分成均等的 3 份。

对齐

Flexbox 的子元素总是在主轴上紧密地排列在一起,没有多余空间可以用来让单个子元素进行单独的对齐,所以 Flex 不存在 justify-items。整个主轴上的对齐是由父容器的 justify-content 属性来统一控制的。它决定了所有子元素作为一个整体如何沿着主轴进行分布和对齐。

与之对比,Grid 就是画格子,格子画完之后,子元素在里面各自精彩,自然可以用 justify-items

命名网格

html 复制代码
<div class="grid-container">
	<header class="header">头部</header>
	<nav class="nav">导航</nav>
	<main class="content1">内容1</main>
	<main class="content2">内容2</main>
	<footer class="footer">底部</footer>
</div>
<style>
	.grid-container {
		display: grid;
		grid-template-areas:
			"header header header"
			"nav content1 content1"
			"nav content2 content2"
			"footer footer footer";

		grid-template-columns: 150px 1fr 1fr;
		grid-template-rows: 100px 1fr 1fr 60px;

		gap: 10px;
		height: 90vh;
	}
	.header {
		grid-area: header;
		background-color: #f0c3a2;
	}
	.nav {
		grid-area: nav;
		background-color: #a2d2ff;
	}
	.content1 {
		grid-area: content1;
		background-color: #b7efc5;
	}
	.content2 {
		grid-area: content2;
		background-color: #b7efc5;
	}
	.footer {
		grid-area: footer;
		background-color: #f2e293;
	}
</style>

不得不说这玩意有点好玩,在配置好行列宽高后,通过文字"画"出页面结构:

css 复制代码
"header header header"
"nav content1 content1"
"nav content2 content2"
"footer footer footer"

网格跨越

除了通过 grid-template-areas "画图",你还可以通过网格跨越设计页面元素。

css 复制代码
.grid-container {
	display: grid;
	grid-template-columns: 150px 1fr 1fr;
	grid-template-rows: 100px 1fr 1fr 60px;
	gap: 10px;
	height: 90vh;
}

.header {
	grid-column: 1 / 4;
	grid-row: 1 / 2;
	background-color: #f0c3a2;
}
.nav {
	grid-column: 1 / 2;
	grid-row: 2 / 4;
	background-color: #a2d2ff;
}
.content1 {
	grid-column: 2 / 4;
	grid-row: 2 / 3;
	background-color: #b7efc5;
}
.content2 {
	grid-column: 2 / 4;
	grid-row: 3 / 4;
	background-color: #b7efc5;
}
.footer {
	grid-column: 1 / 4;
	grid-row: 4 / 5;
	background-color: #f2e293;
}

grid-column 后面的数字表示从第 N 个竖线到第 M 个竖线中间的内容,这或许有点抽象,为什么要用竖线而不是第 N 列 这样的说法?

其实使用第 N 列的写法也有,例如:

css 复制代码
.header {
	grid-column: 1 / span 3;
	grid-row: 1 / span 1;
	background-color: #f0c3a2;
}

如果你要控制某个区间跨度,还是必须要以数字开始,再加 span 数字1 / span 3 代表从第 1 条竖线开始,跨度 3 列。

直接写 grid-column: span 3; 只能代表 3 列,不能控制开始位置。

对齐

Grid 也有 align-justify- 系列的对齐系统,它们的效果也与 Flex 里提到的类似。你可以在这个互动学习网站玩玩 Grid 的 alignjustify 具体属性对元素布局的影响。

place-content 是 CSS 中的一个简写属性,它同时设置了 align-contentjustify-content 这两个属性。它主要用于 Grid 布局,毕竟 Flex 布局比较少将这两个属性同时设置。举个例子

css 复制代码
place-content: center;
place-content: end space-between;

只填一个值的话同时应用到水平垂直,填两个值的话顺序是 place-content: <align-content> <justify-content>;

content 那有没有 items 呢?有的,朋友,如你所猜,就是 place-items,使用方法也是同理可得,就不多赘述了。

Grid 的浏览器支持比 Flex 差一点,不过仍然看好未来,现在用户更新浏览器应该是越来越容易了,保留旧浏览器的情况会比以前大大减少。

Tailwind

Tailwind 把常用的 Flex 与 Grid API 封装为原子类,直接在 class 中组合即可。某种程度上来说,直接从 Tailwind 学习 Flex 布局还好学一点,不过如果你是 Tailwind 的反对者,大可以跳过这一节。

下面用类名重现上文的关键示例:

Flex 基础

  • 容器与方向:
txt 复制代码
flex
flex flex-col
flex-row-reverse
flex-col-reverse
  • 间距与换行:
txt 复制代码
gap-4
gap-x-6 gap-y-2
flex-wrap
flex-nowrap

Flex 对齐

  • 主轴/交叉轴(容器):
txt 复制代码
flex justify-between items-center
flex justify-center items-stretch
  • 多行内容分布(容器,需要 flex-wrap 生效时才有体感):
txt 复制代码
flex flex-wrap content-between
flex flex-wrap content-center
  • 单个子项对齐(子项):
txt 复制代码
self-start
self-center
self-end
self-stretch

Flex 子项尺寸与顺序(子项)

  • 占比/伸缩/基础宽高:
txt 复制代码
flex-1
grow
shrink-0
basis-40

Grid 基础

  • 容器与网格轨道:
txt 复制代码
grid
grid-cols-3
grid-rows-4
  • 使用自定义列/行尺寸(对应上文 150px / 1fr / 1fr 与 100px / 1fr / 1fr / 60px):
txt 复制代码
grid grid-cols-[150px_1fr_1fr] grid-rows-[100px_1fr_1fr_60px] gap-2 h-[90vh]

用跨越重现上文布局

Tailwind 原生未提供 grid-template-areas 的原子类,上文示例可用 col-start/col-end 与 row-start/row-end 组合实现:

  • Header(跨 3 列,1 行):
txt 复制代码
col-start-1 col-end-4 row-start-1 row-end-2
  • Nav(第 1 列,从第 2 行跨到第 4 行):
txt 复制代码
col-start-1 col-end-2 row-start-2 row-end-4
  • Content1(第 2-3 列,第 2 行):
txt 复制代码
col-start-2 col-end-4 row-start-2 row-end-3
  • Content2(第 2-3 列,第 3 行):
txt 复制代码
col-start-2 col-end-4 row-start-3 row-end-4
  • Footer(跨 3 列,1 行):
txt 复制代码
col-start-1 col-end-4 row-start-4 row-end-5

同样可以用简写:

txt 复制代码
col-span-3 row-span-1

(在确定起始线的情况下用 start/end;仅控制跨度时可用 col-span-/row-span-。)

Grid 对齐

  • 同时设置 align-content 与 justify-content(容器):
txt 复制代码
place-content-center
place-content-between
  • 同时设置 align-items 与 justify-items(容器):
txt 复制代码
place-items-center
  • 仅水平/仅垂直(容器):
txt 复制代码
justify-items-start
align-items-end
  • 自动放置方向与紧密填充:
txt 复制代码
grid-flow-col
grid-flow-row-dense

Takeaways

  • Flex 更适合一维 分布与对齐,Grid 更适合二维网格与跨行跨列;实际项目里常用"外层 Grid 划区,内层 Flex 排内容"的混搭策略。
  • 牢记轴心:justify-* 作用在主轴,align-* 作用在交叉轴;切换为 column 后,两者随主轴一并"旋转"。
  • 换行的影响:只有设置了 flex-wrap 时,align-content 才会生效;单行关注 align-items/align-self,多行再谈 align-content
  • Flex 子项尺寸心法:固定 + 自适应 = 固定宽度 + flex: 1(等价 grow-1 shrink-1 basis-0%);除 flex: 1 外,新手谨慎使用更复杂的 flex 简写。
  • Grid 的核心是"画格子":grid-template-columns/rows 配合 fr 单位定义轨道;跨区用 grid-column/grid-row(如 1 / 4 或 1 / span 3);也可用 template-areas 直观命名布局。
  • 对齐总览:Grid 还支持 justify-items/align-items,以及 place-content/place-items 的简写组合,既能控制"内容整体",也能控制"单元格内"。
  • 兼容性与实践:Grid 支持略逊于 Flex,但现代浏览器基本可用;旧环境保守选 Flex,新项目优先考虑 Grid + Flex 混搭。

推荐阅读

相关推荐
AI大模型-小华34 分钟前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子3 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅3 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni3 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学5 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端
开普勒chr5 小时前
css样式diaplay:"contents"的妙用
css
赵庆明老师5 小时前
Vben精讲:21-详解web-antd:tsconfig.json
前端·json·vim
wc885 小时前
微软EDGE浏览器功能学习
前端·学习·edge
Csvn6 小时前
🎯 原生 `<dialog>` 元素:终于可以扔掉一半的自定义弹窗组件了?
前端