尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

CSS Grid实战指南:告别Flexbox硬拼,搞定二维页面布局

发布时间:2026/9/18 11:11:18

资讯中心
01
ARTICLE

CSS Grid实战指南:告别Flexbox硬拼,搞定二维页面布局

CSS Grid实战指南:告别Flexbox硬拼,搞定二维页面布局
我做页面布局做了这么多年从表格布局一路用到 Flexbox再到现在的 CSS Grid感受最深的一点是Grid 就是为网页排版量身定制的二维布局神器。它跟我们以前用的任何布局方案都不一样因为它从底层就把行和列当成了第一公民。如果你还在靠 Flexbox 加各种百分比、calc、负 margin 去硬拼复杂排版那这篇文章就是为你准备的。这篇文章不会只贴一段官方文档式的语法说明我会从实际项目出发把 Grid 的核心概念、关键属性、真实场景案例和我在实战中踩过的坑都整理出来。无论你是刚接触 Grid 的初学者还是已经用了一阵子但总觉得没吃透的开发者都能在这里找到可以直接照搬的写法和脑子里那根什么时候该用谁的弦。1. 搞懂 Grid 之前先搞清楚它和 Flexbox 的定位差异1.1 一维与二维Flexbox 是串串Grid 是棋盘很多人一上来就问有了 Flexbox 为什么还要 Grid它俩是不是重复了其实完全不重复核心差异就在一维和二维这两个词上。Flexbox 的精髓是一维布局它一次只处理一个方向——要么横向排要么纵向排。主轴上的项目可以灵活伸缩、换行但副轴方向的排布其实是顺便的你很难用 Flexbox 精确控制第二行某个项目在第几列。类比一下Flexbox 就是一根烤串签子所有东西都串在这一根轴线上虽然能串不少但终究是单线操作。Grid 则是二维布局它同时管理行和列两个方向数据结构和 Excel 表格一样有行、有列、有单元格。你在 Grid 里定义一个项目跨几列、跨几行是从结构上就确定下来的而不是靠计算宽度或高度挤出来的。所以碰到页面骨架、卡片墙、杂志式排版这类横竖都要管的场景Grid 是天然的正确答案。1.2 什么场景该用 Grid带着问题看效果我自己的经验准则很简单整体骨架用 Grid内部细节用 Flexbox。页面级布局通常就是 Grid 的主场后台管理系统的侧边栏顶栏内容区电商网站的商品卡片墙新闻门户的板块交错排列这些都需要同时控制行和列用 Grid 写起来干净得让人感动。举一个我印象很深的例子。以前用 Flexbox 做商品列表要保证每行固定 4 列、卡片等宽、最后一行不满也要左对齐我得写 flex-wrap 加 width 百分比还得考虑 gap 会不会把宽度撑爆加上响应式还得改媒体查询。换成 Grid 后一行grid-template-columns: repeat(auto-fill, minmax(240px, 1fr))就全解决了——列数自动适配、宽度弹性伸缩、换行对齐全部内置。这种体验上的差距只有亲手写过一遍才懂。2. 核心概念一次吃透容器、项目、网格线与六大关键属性2.1 从一行代码开始display: grid 与网格容器Grid 的项目结构跟 Flexbox 类似分为容器和项目两层。给一个元素加display: grid它就变成了网格容器它的直接子元素自动变成网格项目。.container { display: grid; }光是这一行你就能看到容器内部发生了变化子元素不再像普通块级元素那样上下堆叠而是会按默认规则排成单列多行的网格。不过这只是起点真正决定网格形态的是接下来要说的行列定义。网格容器内部有几组核心概念需要先在大脑里建立模型网格线Grid Line划分行列的分界线纵向的叫列线横向的叫行线。注意网格线编号从 1 开始不是 0。网格轨道Grid Track两条相邻网格线之间的区域就是一行或一列。网格单元Grid Cell单个行列交叉出的格子是网格的最小单位。网格区域Grid Area由四条网格线围成的矩形区域可能是多个单元格拼起来的。这四个概念是你之后阅读任何 Grid 教程的地基。搞懂它们grid-column、grid-area这些属性就不再是魔法咒语。2.2 fr 单位、repeat() 和 minmax()灵活刃与硬底线定义行列最常用的三个工具是fr单位、repeat()函数和minmax()函数。fr是 fraction份额的缩写它表示剩余空间的分配比例不是固定宽度。这跟 Flexbox 里的flex: 1原理类似但用起来更直观。.container { display: grid; grid-template-columns: 1fr 2fr 1fr; gap: 16px; }这里的1fr 2fr 1fr表示三列第二列占两份第一、三列各占一份。具体怎么算假设容器宽度 1000pxgap 是 16px 且有两个间隙总共是 32px剩余空间就是 1000 - 32 968px。一份是 968 ÷ 4 242px所以三列分别是 242px、484px、242px。注意计算顺序是先扣除 gap再按比例分配这个顺序在设置百分比列宽时特别容易踩坑。repeat()是用来简化重复写法的。repeat(3, 1fr)等价于1fr 1fr 1fr它还能配合其他写法混用比如grid-template-columns: 200px repeat(2, 1fr)表示第一列固定 200px后两列平分剩余空间。minmax()则是给轨道设定一个范围常见搭配是minmax(200px, 1fr)意思是列宽最小 200px有额外空间时按 1fr 扩大。这个函数在响应式布局里是香饽饽后面做卡片墙案例时会再见到。2.3 网格线定位让项目想跨几列就跨几列定义好网格轨道之后默认情况下每个子元素会按顺序自动填进一个网格单元里。但实际版面往往需要某个区域占两列、某篇文章占两行这时候就要用网格线的定位属性。.item-feature { grid-column: 1 / 3; grid-row: 1 / 3; }grid-column: 1 / 3表示这个项目从第 1 条列线开始到第 3 条列线结束也就是跨越了第 1 列和第 2 列。grid-row: 1 / 3同理跨两行。这里的编号判断方式我总结了一句口诀写的是网格线编号不是列数编号。你要跨两列终点线的编号是起始线编号加 2不是加 1新手最容易在这里数错。如果嫌计算终点麻烦可以用span关键字grid-column: 1 / span 2表示从第 1 条列线开始横跨 2 列。语义上更接近这个元素要占多大可读性也更好我自己更推荐这种写法。2.4 grid-template-areas用画图替代数线网格线定位用多了你会发现复杂布局里数编号特别容易头晕。Grid 为此给了一个直观到离谱的写法grid-template-areas。它允许你用 ASCII 图形来定义页面骨架比如一个经典的后台布局.layout { display: grid; grid-template-columns: 220px 1fr; grid-template-rows: 60px 1fr 40px; grid-template-areas: header header sidebar main footer footer; min-height: 100vh; }我特别喜欢这个特性的原因是它让布局变成了一幅地图每个字符串代表一行每个单词代表一个单元格区域。你只需要在子元素里写grid-area: header;、grid-area: sidebar;元素就会自动对号入座。改布局也只需要改这几行字符串视觉上立刻能看出结构变化完全不用去算线号。grid-template-areas有个硬性要求每个单元格都必须有名字区域形状必须是矩形。你不能写出一个 L 形的区域比如第一行有 a b第二行只有 a这种定义会直接报错。但它的容错方式很友好报错信息会提示哪一行没对齐。3. 对齐与间距Grid 里容易迷糊的一组属性3.1 justify-items 和 align-items管的是格子里的项目Grid 的对齐属性分两组很多人在这里栽跟头。第一组justify-items和align-items控制的是项目在单元格内部的对齐方式从容器上设置所有子项目生效。justify-items控制水平方向可选 start、end、center、stretch。align-items控制垂直方向可选 start、end、center、stretch。默认值是stretch也就是项目默认会拉伸填满整个单元格。这就是为什么 Grid 里的子元素不设置宽高时会自动把格子撑满。如果你想做一个内容居中的卡片可以设置place-items: center它其实是align-items: center; justify-items: center;的简写。在布局一个按钮、一张图片、一段文字时这个用法能省掉大量的 margin 凑居中的操作。3.2 justify-content 和 align-content管的是整个网格的位置第二组justify-content和align-content控制的是整个网格轨道组在容器里的位置。什么时候会生效当网格总宽度小于容器宽度或者总高度小于容器高度时才会看出区别。举个实际例子容器宽 1000px你定义了三列固定宽度 200px网格总宽度只有 600px剩下 400px 不知道去哪了。此时justify-content: center会把这三列整体居中justify-content: space-between会让三列贴左、右两端中间一列居中这种分布方式和 Flexbox 的justify-content效果一致。搞混这两组属性的后果很典型你想把内容居中结果写了justify-content: center发现毫无变化因为项目本身已经默认填满格子了。先判断是放在单元格里还是整个网格放在容器里再选对应的属性组就不会踩坑。3.3 gap间距的正确打开方式Grid 的间距属性gap是我用回不去的功能之一。它代替了以前 Flexbox 里靠 margin 加负 margin 甚至 nth-child 选择的野路子。gap可以同时设置行距和列距.container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px 24px; }这里16px是行间距24px是列间距。只写一个值则两个方向相同。gap不会像 margin 那样把项目向外推导致容器溢出也不会让首尾元素多出额外间距它只负责项目之间的空隙。按理说一个这么合理的属性应该早就普及了但确实还有不少老项目还在用 margin 方案如果你维护这类代码可以找机会顺手升级一下。4. 实战三步走三个高频布局场景完整拆解4.1 场景一经典后台管理系统骨架后台管理界面几乎是 Grid 布局的标准教材。它需要固定的侧边栏、自适应宽度的主体、顶栏和底部栏结构非常规整。用 Flexbox 做这个需要嵌套好几层容器而用 Grid 只需要一个容器加grid-template-areas。div classlayout header classheader顶部导航/header aside classsidebar侧边菜单/aside main classmain主要内容区/main footer classfooter底部版权/footer /div.layout { display: grid; grid-template-columns: 220px 1fr; grid-template-rows: 60px 1fr 40px; grid-template-areas: header header sidebar main footer footer; min-height: 100vh; } .header { grid-area: header; } .sidebar { grid-area: sidebar; } .main { grid-area: main; } .footer { grid-area: footer; }min-height: 100vh保证了页面骨架至少撑满整个视口高度即使内容不够footer 也保持在底部。这个骨架最爽的地方在于响应式适配在移动端只要在媒体查询里改几行区域字符串布局立刻从左右结构变成上下结构media (max-width: 768px) { .layout { grid-template-columns: 1fr; grid-template-areas: header main sidebar footer; } }侧边栏在移动端被挪到了主内容后面视觉上先看内容再看菜单这种调整在旧方案里往往要改 HTML 结构或大动 CSS在 Grid 里就是改几行字符串的事。4.2 场景二自适应商品卡片墙商品列表、图片库、博客卡片这类数量不确定、每行都想自动适配的网格场景用repeat(auto-fill, minmax(...))是最佳解法。.card-wall { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }这一行的意思是自动填充列每一列最小宽度 240px有剩余空间时按 1fr 分配。容器是 1000px 宽时能排下 4 列240×4 gap×3 1008px实际计算时浏览器会智能调整容器到 800px 时自动变成 3 列到 500px 时变成 2 列。整个过程不需要一个媒体查询。这里要注意auto-fill和auto-fit的区别这俩看起来差不多行为却完全不同。auto-fill会保留空轨道即使项目不够多空白列仍然占位auto-fit则会把空轨道折叠掉让已有项目拉伸填满整行。单行情况下auto-fit能让一两个项目铺满整行更美观多行商品墙则用auto-fill更符合预期。你可以自己开个 DevTools 拖动容器宽度用同屏对比的方式感受差别。4.3 场景三杂志风格交错排版前面两个场景的网格都是规规矩矩对齐的第三个场景来点不规则。杂志排版常见做法是头条大图占据两列两行其他小卡片正常铺排偶尔穿插一些横向跨度不同的模块。div classnews-grid article classcard feature头条大图/article article classcard普通卡片 1/article article classcard普通卡片 2/article article classcard wide横向宽卡/article article classcard普通卡片 3/article /div.news-grid { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 120px; gap: 12px; } .feature { grid-column: span 2; grid-row: span 2; } .wide { grid-column: span 2; }grid-auto-rows: 120px很关键。因为这里没有用grid-template-rows定义行高而是允许浏览器自动生成行如果不设定固定行高所有行都会被内容撑成不同高度交错效果就会乱掉。给一个固定 120px 的基础行高配合span 2的大卡片占 240px 高网格看起来才会有整齐中的变化感。如果卡片顺序导致网格里出现空洞比如某个跨两列的元素把后续项目挤到下一行留下一个空格子可以给容器加grid-auto-flow: dense让后续项目回填空位。但要注意dense会改变项目的视觉顺序让 DOM 顺序和视觉顺序不一致屏幕阅读器和键盘导航也会跟着乱如果是靠前的位置有重要内容不建议无脑开启。5. 避坑指南Grid 实战中高频出现的问题与排查5.1 自动生成的行列尺寸失控Grid 有个特性是隐式网格。当项目数量超出你显式定义的行列轨道时Grid 会自动创建新的轨道来放这些项目。问题是隐式轨道的默认尺寸是auto也就是由内容撑开。比如你定义了grid-template-columns: repeat(3, 1fr)放 5 个项目前 3 个在第一行后 2 个被系统自动创建了一个新行这个新行的高度由第 4、5 个项目的内容高度决定很可能比第一行矮或高导致卡片不等高。解决办法是显式设置隐式轨道尺寸grid-auto-rows: 1fr或固定值。这样不管项目多少、内容多少所有自动生成的行都会保持统一高度。这个属性我几乎每写一个卡片墙都会带上属于预防性写法。5.2 fr 和百分比混用时的宽度账fr是在扣除固定尺寸和 gap 之后分配剩余空间的如果你混用了固定列宽200px、百分比列宽30%和1fr计算顺序是先处理固定和百分比再让 fr 分剩下的。有一个很容易被忽视的细节百分比的基准是容器宽度但 Grid 项目默认不包含border-box之外的间距预算所以30%是实打实按容器宽度算的而不是按扣除 gap 后算的。如果页面出现横向滚动条或者列宽分配和预期不符先检查是不是百分比列宽加 gap 把总宽度撑超了。我的习惯是尽量统一用fr和minmax除非列宽真的必须严格按容器比例否则避免在 Grid 里混用百分比。5.3 项目内部再布局别把 Grid 塞到最深层Grid 虽然能处理二维布局但它的定位是布局框架。如果一个卡片内部只有一行文字加一个按钮这种内部小结构再去定义 Grid 就有点大材小用了用 Flexbox 或 block 布局更轻快。网格项目的子元素不会自动变成网格项目网格只作用于容器的直接子元素这一层。你如果发现写了display: grid但内部某些嵌套元素没有按预期排列多半是把 Grid 写在了错误的层级。记住Grid 管一层Flexbox 管一层两者可以嵌套。这也是我推荐页面骨架 Grid 模块内部 Flexbox组合拳的原因。5.4 问题排查速查表常见现象可能原因解决办法项目没有按行列排列忘了在容器上写display: grid确认容器元素设置了display: grid列数不是预期数量repeat参数写错或auto-fill/auto-fit用反检查grid-template-columns定义单行效果优先选auto-fit卡片高度不一致隐式行高默认auto加grid-auto-rows: 1fr或固定高度网格线跨行跨列没生效终点线编号数错用了 0 作为起始编号确认编号从 1 开始改用span语法justify-content没反应网格总宽度正好等于容器宽度先让网格总宽度小于容器宽度再测试gap 不生效用了旧版grid-gap但浏览器版本旧现代浏览器直接写gap兼容旧环境保留grid-gap声明视觉顺序和 DOM 顺序不一致开启了grid-auto-flow: dense确认对无障碍可接受或者关闭 dense 改用显式定位5.5 Grid 和 Flexbox 到底怎么选最后的选型问题我用一句话总结内容在一条线上流动用 Flexbox整体骨架在二维平面分配用 Grid。细节一点说导航栏、按钮组、表单横向排列这些一行东西永远属于 Flexbox页面整体布局、卡片墙、需要同时保证行和列对齐的场景属于 Grid。二者不是竞争关系是互补关系好的页面通常两种都在用。兼容性方面现代浏览器对 Grid 的支持已经非常成熟移动端和桌面端的 Chrome、Firefox、Safari、Edge 都稳定支持日常业务可以放心用。如果非要照顾上古浏览器Grid 的属性本身支持supports做降级判断给不支持的环境准备一套 Flexbox 兜底布局但说实话这类场景在现在的项目里已经越来越少了。我个人在使用 Grid 之后最大的变化是写页面骨架的焦虑感没了。以前那些左侧固定右侧自适应两边定宽中间弹性的圣杯需求现在都是几行声明的事。从第一次用grid-template-areas画完整个后台布局到现在我已经很少再为一个版面结构纠结超过五分钟。如果你还在用老方案硬撑复杂排版找个小页面用 Grid 重构一遍试试那种这也能一行搞定的爽快感很容易上瘾。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。