CSS 布局:Flex 和 Grid 怎么选,附常见坑

CSS 布局:Flex 和 Grid 怎么选,附常见坑

做前端布局时,最常纠结的问题不是"怎么写",而是"该用 Flex 还是 Grid"。一句话先说结论:**一维布局用 Flex,二维布局用 Grid**。一维指只沿一个方向排:横着一排或竖着一列;二维指行和列都要同时控制,比如整体页面骨架、卡片墙。

一、Flex:管"一排"或"一列"

Flex 适合导航栏、按钮组、头像加文字、垂直居中这类场景。容器定方向,子项沿主轴排。

```html

<nav class="nav">

<a href="#">首页</a>

<a href="#">文章</a>

<a href="#">关于</a>

<span class="spacer"></span>

<button>登录</button>

</nav>

```

```css

.nav {

display: flex;

align-items: center; /* 交叉轴居中 */

gap: 16px;

}

.spacer {

flex: 1; /* 把登录按钮顶到最右边 */

}

```

再看一个经典需求:未知高度的盒子水平垂直居中。

```css

.center {

display: flex;

justify-content: center; /* 主轴居中 */

align-items: center; /* 交叉轴居中 */

min-height: 200px;

}

```

记住一对容易混的概念:`justify-content` 管主轴,`align-items` 管交叉轴。默认主轴是横向,所以"水平居中"是 `justify-content: center`,改成 `flex-direction: column` 后,主轴变竖向,两者的作用就互换了。

二、Grid:管"行列一起排"

Grid 适合页面骨架、卡片列表、表单两列对齐。先画格子,再把内容放进格子。

```html

<div class="layout">

<header>头部</header>

<aside>侧边栏</aside>

<main>正文</main>

<footer>页脚</footer>

</div>

```

```css

.layout {

display: grid;

grid-template-columns: 200px 1fr;

grid-template-rows: auto 1fr auto;

grid-template-areas:

"header header"

"aside main"

"footer footer";

gap: 16px;

}

header { grid-area: header; }

aside { grid-area: aside; }

main { grid-area: main; }

footer { grid-area: footer; }

```

卡片自适应列数,不用写媒体查询也能"能排几列排几列":

```css

.cards {

display: grid;

grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));

gap: 16px;

}

```

`minmax(220px, 1fr)` 的意思是:每列最窄 220px,有剩余空间时按 1fr 平分。`auto-fill` 会先把格子占满,`auto-fit` 则会把空列折叠掉、让已有卡片拉宽,做"不足一行时拉满"用 `auto-fit` 更合适。

三、对照表:怎么选

| 场景 | 选谁 | 原因 |

|---|---|---|

| 导航栏、工具条、按钮组 | Flex | 只有一排,间距和对齐一把梭 |

| 垂直居中、两端对齐 | Flex | 主轴加交叉轴两个属性就够 |

| 页面骨架、左右加上下结构 | Grid | 行列、区域一次定义清楚 |

| 卡片墙、图库 | Grid | 列数、间距、对齐由格子统一管 |

| 表单标签加输入框对齐 | Grid | 两列对齐比 Flex 套娃更稳 |

| 内容数量不确定、只管横向流动 | Flex + flex-wrap | 换行后按内容自然流动 |

拿不准时可以这样判断:先问"行和列是否都要对齐"。只要答案是"是",就优先 Grid;只关心一排或一列的顺序和间距,就用 Flex。两者也可以嵌套:外层 Grid 定骨架,内层 Flex 管一排里的对齐,这是实际项目里最常见的组合。

四、常见坑

1. Flex 子项被内容撑爆,挤不回去

长单词或长链接会把 Flex 子项撑宽,`flex: 1` 也压不住。原因是 Flex 子项默认 `min-width: auto`,不会小于内容宽度。解法是给可能溢出的子项加 `min-width: 0`:

```css

.item {

flex: 1;

min-width: 0; /* 允许收缩,配合 overflow 截断才有效 */

overflow: hidden;

text-overflow: ellipsis;

white-space: nowrap;

}

```

2. 忘了 flex-wrap,内容溢出容器

默认 `flex-wrap: nowrap`,子项再多也不会换行,只会挤压或溢出。做标签、筛选条件这种数量不定的横排时,记得写 `flex-wrap: wrap`,并用 `gap` 控制间距,不要再靠子项 margin 硬凑。

3. flex: 1 不是 flex-grow: 1

`flex: 1` 等价于 `flex: 1 1 0%`,基准是 0,会按比例重新分配全部空间;而只写 `flex-grow: 1` 时,`flex-basis` 仍是 `auto`,先按内容宽度占位,再分剩余空间。两者在内容长短不一时结果差别很大,想等分就写 `flex: 1`。

4. Grid 里 fr 不是百分比

`1fr` 分的是"剩余空间",不是容器总宽度的固定比例。`grid-template-columns: 200px 1fr` 里,1fr 拿到的是减去 200px 和 gap 之后的部分;如果列里有很长的内容,`minmax(0, 1fr)` 才能防止该列被内容撑大。

5. auto-fill 和 auto-fit 用反

两者只在"格子多于内容"时有区别:`auto-fill` 保留空列,卡片保持原宽、右边留白;`auto-fit` 折叠空列,卡片拉宽填满一行。想要"卡片墙不满一行也铺满"选 `auto-fit`,想要"固定列宽、右边留白"选 `auto-fill`。

6. 居中只写一半

`justify-content` 和 `align-items` 只管容器里的子项整体位置;Grid 里想让某个格子里的内容居中,用 `place-items: center`(等于 `align-items` 加 `justify-items`)更直接。调试时先确认:你居中的是"子项在容器里的位置",还是"内容在格子里的位置",两者属性不一样。

五、收尾检查清单

发布前对着过一遍:方向是单维还是双维;Flex 容器有没有按需写 `flex-wrap`;可能溢出的子项有没有 `min-width: 0`;Grid 列宽用的是 `fr` 还是固定值、需不需要 `minmax`;`auto-fill` 还是 `auto-fit` 是否符合预期。选对工具,布局代码会短一半,返工也会少一半。

相关推荐
计算机魔术师1 小时前
科技巨头砸7400亿押注AI,为什么苹果成了唯一赢家?
前端
QianhangQianping1 小时前
撤销重做不是「存快照」:一个可视化编辑器的Operation 设计
java·前端·数据库·typescript·编辑器·前端架构·撤销重做
Nymph_Zhu2 小时前
pdf转换markdown预览及内容互相点击定位
前端·pdf·vue3·markdown·element-plus
计算机魔术师2 小时前
Google 一天蒸发5000亿,Reddit 靠 AI 训练喂得饱自己却饿死
前端
小大宇2 小时前
Vue知识点-ElementPlus-05 输入框
前端·javascript·vue.js
东鹏特饮2 小时前
本机状态监控页面html
运维·css·html·css3
软件技术NINI2 小时前
基于SpringBoot和Vue的摇滚乐鉴赏网站
vue.js·spring boot·后端·spring·html·毕业设计·毕设
l1m0_2 小时前
AI设计工具有哪些?Paico、Pixso AI、墨刀AI、Lovable、Codex怎么选
前端·人工智能·ai·设计·墨刀·codex·pixso
web打印社区2 小时前
Lodop在Edge和双核浏览器-先分清内核
前端·javascript·edge·pdf·ecmascript·html5