CSS布局实战:从Flex到Grid的完整避坑指南

全文约2200字,预计阅读8分钟。

页面挤成一团?换行错位?居中怎么都对不齐?做过两三个后台页面之后,基本都会和这几个问题反复交手。Flex 解决了一维排列,Grid 补上了二维网格,但这两套布局写起来都有不少"看起来对、跑起来歪"的坑。这篇文章把日常最常写的几种布局串一遍,附上代码和踩坑记录,尽量让你下次少调两小时 DevTools。

01 前言:为什么布局要从 Flex 说到 Grid

Flexbox 面向一维方向:一行或者一列,负责"这一排元素怎么排"。Grid 面向二维网格:行和列同时定义,负责"整个页面骨架怎么切"。两者不是替代关系,而是分工------页面大骨架用 Grid,局部组件用 Flex。

很多人刚学的时候把 Grid 当"更强的 Flex",结果写出来的东西又长又难维护。正确的思路是先看这堆元素是一维关系还是二维关系,再选模型。

02 常见布局诉求先对号入座

日常需求大致就这几类:

  • 顶部一条导航,左边 logo、右边菜单:一维横排,Flex;
  • 卡片列表一行三张、自动换行:一维排列,Flex 或 Grid 都行;
  • 整页分为 header / aside / main / footer:二维骨架,Grid;
  • 表单里 label 和 input 两列对齐:二维网格,Grid;
  • 弹窗内容水平垂直居中:Flex 三行代码搞定。

先判断维度,再开写,能省掉一半返工。

03 Flex 布局核心与三个高频踩坑

3.1 容器与项目两条轴

给父元素加 display: flex 之后,它的直接子元素就变成 flex item。主轴由 flex-direction 决定,交叉轴与之垂直。常用属性分两组记:

css 复制代码
.container {
  display: flex;
  justify-content: center;  /* 主轴对齐 */
  align-items: center;      /* 交叉轴对齐 */
  gap: 12px;                /* 项与项间距 */
}

记住一个口诀:justify 管主轴,align 管交叉轴。写反的时候页面不会报错,只是怎么调都不对。

3.2 经典水平垂直居中

css 复制代码
.center {
  display: flex;
  justify-content: center;
  align-items: center;
}

三行代码搞定,比以前套 position: absolute 加 transform 稳得多,而且内容尺寸变化时不会偏。

3.3 踩坑一:flex: 1 不是 width: 100%

新手常写:

css 复制代码
.item { flex: 1; }

然后发现内容多的时候元素被挤变形。原因是 flex: 1 等于 flex-grow: 1; flex-shrink: 1; flex-basis: 0%,它允许元素收缩。内容撑不开时想让它均分,应该写:

css 复制代码
.item { flex: 1 1 0; min-width: 0; }

3.4 踩坑二:min-width: auto 导致内容溢出

flex item 的 min-width 默认是 auto,意思是"最小不能小于内容宽度"。子元素里放一段长文本或者一个表格,整排就会溢出容器。修复方式很直接:

css 复制代码
.item { min-width: 0; }

加完之后文本才会正常换行,而不是把兄弟元素顶出屏幕。

3.5 踩坑三:gap 出来之后就别再用 margin 凑间距

老代码里常见 margin-right: 12px 然后给末项清零。gap 普及之后直接写:

css 复制代码
.row { display: flex; gap: 12px; }

不需要 :last-child 清零,换行时也不会多出半截间距。

3.6 换行场景记得 flex-wrap

一排按钮在窄屏被挤变形,多半是漏了 flex-wrap:

css 复制代码
.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

不写的话,主轴空间不够时子元素会按 flex-shrink 压缩,文字标签直接挤成两行。写成 wrap 之后放不下的项自动换到下一行,配合 gap 间距依然均匀。

Flex 与 Grid 的常见差异可以对照看:

维度 Flex Grid
方向 一维,一条主轴 二维,行和列同时定义
间距 gap 兼容良好 gap 支持行列双向
适合 导航、按钮组、列表项 页面骨架、表单、仪表盘
内容驱动 由内容决定尺寸 由轨道定义决定尺寸

04 Grid 布局核心与三个高频踩坑

4.1 二维网格思维

Grid 的核心是"先画网格,再放东西":

css 复制代码
.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: 60px 1fr 40px;
  grid-template-areas:
    "header header"
    "aside  main"
    "footer footer";
  gap: 12px;
}
.header { grid-area: header; }
.aside  { grid-area: aside; }
.main   { grid-area: main; }
.footer { grid-area: footer; }

页面骨架用 grid-template-areas 写,结构一眼能读懂,比嵌套三层 div 清爽。

4.2 repeat、fr 与 minmax

写卡片列表时,常用这套组合:

css 复制代码
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}

含义是:每列最小 240px,剩余空间按 fr 均分,装得下几列就放几列。

4.3 踩坑四:auto-fill 和 auto-fit 弄混

两者在子项数量少的时候差异明显:

  • auto-fill:轨道先把列排满,剩下的空轨道保留;
  • auto-fit:空轨道折叠,现有子项被拉伸撑满整行。

一行两个卡片时,auto-fit 会把两个卡片拉得很宽,auto-fill 则保持 240px 宽、右侧留白。想让卡片始终保持设计宽度用 auto-fill,想让少量卡片撑满用 auto-fit。

4.4 踩坑五:gap 和 margin 别叠加

Grid 里 gap 已经控制了行列间距,再给 item 加 margin 会出现间距翻倍,而且换行处很难看。统一用 gap,个别特殊项再单独微调。

4.5 踩坑六:1fr 不等于剩余空间均分

grid-template-columns: 1fr 1fr 看上去均分,但如果其中一列内容特别长,1fr 实际是 minmax(auto, 1fr),长内容会把这列撑宽。需要严格等宽时写:

css 复制代码
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);

4.6 实战:用 Grid 写一个经典后台骨架

下面这段是后台页面最常见的骨架,可以直接抄去改:

css 复制代码
.admin {
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  grid-template-rows: 56px minmax(0, 1fr);
  min-height: 100vh;
}
.admin .topbar  { grid-column: 1 / -1; }
.admin .sidebar { overflow: auto; }
.admin .content { overflow: auto; padding: 16px; }

要点是中间内容区用 minmax(0, 1fr) 而不是 1fr,否则里面的表格或者横向滚动区会把整列撑宽,顶栏错位。窄屏下再用媒体查询把侧边栏收成顶部抽屉:

css 复制代码
@media (max-width: 768px) {
  .admin { grid-template-columns: 1fr; }
  .admin .sidebar { display: none; }
}

05 Flex 和 Grid 怎么选

一个判断流程:

  1. 元素是排成一条线(横或竖),用 Flex;
  2. 元素要同时按行和列对齐(表单、仪表盘、整页骨架),用 Grid;
  3. 不确定时,先写 Flex 跑通,局部二维区域再换 Grid,不要一步到位全 Grid。

实践中常见的组合是:外层 Grid 切页面大块,内层 Flex 排按钮、排菜单项。两者混用完全合法。

06 兼容性速查

现代浏览器对 Flex 的支持已经非常完善,Grid 自 Chrome 57、Safari 10.1 起全量支持 gap、grid-template-areas 等核心特性。如果项目还要兼容很老的机型,在引入新特性前先查目标浏览器版本矩阵,并在真实设备上跑一遍窄屏布局。

07 总结

  • 一维排列用 Flex,二维骨架用 Grid,别用反;
  • flex 容器上 justify 和 align 管的是不同轴,写反是最常见 bug;
  • flex item 记得 min-width: 0,长文本才不会溢出;
  • Grid 里 auto-fill 保宽、auto-fit 撑满;
  • 间距统一交给 gap,少写 :last-child 清零。

布局没有银弹,把这几个高频坑记牢,日常写页面会顺很多。下次写之前先花十秒钟判断维度,再挑模型,比写完之后来回改样式要省心得多。

相关推荐
用户5508492902562 小时前
前端接口请求层怎么封装?一个可落地的请求方案
前端
MetWeave2 小时前
跟着一条 SPECI 走流水线:从电报到界面
前端
Helix2502 小时前
Chrome 开发者工具进阶:长截图、网络调试与性能分析
前端·chrome·chrome devtools·使用技巧·性能分析·开发者工具·长截图
liangshanbo12153 小时前
面试题:Webpack 的 publicPath 有什么作用?
前端·webpack·node.js
mjhcsp3 小时前
DeepSeek V4.1 Flash 批量处理效能实测
java·前端·数据库
CHEEVEN_QY4 小时前
新能源汽车电池托盘FSW量产的工艺稳定性控制
java·前端·汽车
Alice-YUE4 小时前
前端 × AI:从 Cursor 到 Transformer,一份完整认知路径
前端·人工智能·transformer·ai编程·前端开发·cursor
Code_Solitude4 小时前
C语言:关于二维数组的作业总结
java·c语言·前端
acd120095 小时前
前端随笔:数据明明变了,Vue 页面就是不更新
前端·javascript·vue.js