Skip to main content
Grid 我是先把二维骨架画出来再写属性,比一层层套 Flex 省心得多。

Q1: Grid 到底比 Flex 强在哪里?

1

Flex 的一维困境

Flexbox 是一维布局系统的王者。它的思想是”把元素像烤串一样串在主轴上’。如果烤串太长了换行(flex-wrap),新的一行对上一行是绝对无感知的。你根本无法保证上下两行的格子能完美对齐形成严密的矩阵。
2

致命痛点: 二维矩阵的崩溃

为了画一个 3x3 且上下绝对对齐的九宫格,必须给容器加 flex-wrap: wrap,必须精确计算每个子元素的 width: 33.33%,如果里面还要有缝隙(gap),数学计算的百分比容易因浮点数精度在某些浏览器里崩溃换行。
3

Grid 的二维上帝视角

Grid(网格布局)是 CSS 历史上第一个也是唯一一个纯粹的二维布局系统。在写 Grid 时,你就像上帝一样俯视整个屏幕,直接用画笔在虚空中划定”行(Row)“与”列(Column)“的钢铁防线。元素就像是填字游戏里的字母,被精准地卡在指定的坐标系统里。
4

fr 单位与轨道构建机制

Grid 引入了颠覆性的 fr(Fraction)单位,它是在引擎物理减去了所有 gap 和固定 px 占位之后,专门用来公平瓜分”绝对剩余空间’的尚方宝剑,比百分比优越一万倍。配合 repeat(auto-fill, minmax(200px, 1fr)) 这行代码,引擎会根据屏幕宽度自动计算最多能塞入几列,直接干掉几十行繁琐的媒体查询,实现极致流畅的响应式降级。
5

关键洞察: auto-fill 与 auto-fit 的幽灵轨道

当子元素填不满容器时,两者的裂变就发生了:auto-fill 是刻板的机器,会继续在虚空中创建不可见的”幽灵轨道’来填满容器;而 auto-fit 更聪明,它会瞬间将空闲轨道的尺寸折叠崩塌为 0,把空出来的巨大可用空间交还给已有元素的 fr 去瓜分。理解这个”幽灵轨道”机制,是掌握 Grid 响应式布局的关键钥匙。
Grid 与 Flex 不是替代关系。落到具体页面上,我更常用的分工是: Grid 解决的核心问题:
Grid 让二维空间的布局从”嵌套一维容器”变成了”直接声明坐标”,是 CSS 布局的最终形态。

🚫 Flex 强行画矩阵

为了画一个 3x3 且上下绝对对齐的九宫格。必须给容器加 flex-wrap: wrap,必须精确计算每个子元素的 width: 33.33%,如果里面还要有缝隙(gap),数学计算的百分比容易因浮点数精度在某些浏览器里崩溃换行。

✅ Grid 天生矩阵

只需在父容器大喊一句魔法咒语:grid-template-columns: repeat(3, 1fr)。引擎立刻在虚空中斩出绝对平分的三条铁轨,子元素自动填入,毫厘不差。
Grid 布局就像城市规划师在白纸上画的规划图。你先用 grid-template-columns 和 grid-template-rows 画好马路和街区(行列轨道),然后把商场、公园、住宅(子元素)精确地放进指定的格子里。fr 单位就像”按比例分配土地”——先扣掉公共设施(gap 和固定尺寸),剩下的按比例公平瓜分。跟 Flex 的”由内向外”不同,Grid 是”先规划再塞人”,骨架纹丝不动。
回答时先说”为什么’(Flex 一维的矩阵困境),再说”怎么解决”(Grid 的二维坐标系统)。重点是理解 Grid 的设计哲学—“从外向内”的绝对统治,而不是背诵属性。

Q2: fr 单位与 auto-fill 的技巧

Grid 布局引入了一个颠覆所有经典单位(如 px, %)的顶级空间分配单位:fr (Fraction,分数)。
fr 比百分比(%)优越一万倍的地方在于:百分比是基于总宽度硬算的,一旦你加上了 gap(网格间隙),百分比就会瞬间撑爆容器!而 fr 的算法与 flex-grow 相似:它是在引擎物理减去了所有的 gap 以及固定 px 占位之后,专门用来公平瓜分”绝对剩余空间”的尚方宝剑。

fr vs % 的关键区别

这是现代响应式布局中最昂贵、有力的一行代码。
  • auto-fill:根据当前屏幕物理宽度自动计算”最多能塞入几列’。
  • minmax(200px, 1fr):每列的底线是 200px,如果塞满后还有剩余空间,用 1fr 均匀分发。
  • 仅需这一行代码,直接干掉几十行繁琐的媒体查询(Media Queries),实现极致流畅的响应式降级!
auto-fill 就像一个智能停车场:场地有多宽,就自动算出能划多少个车位(每车位最少 200px)。1fr 就像”如果有空地,大家均分’。而 auto-fit 则更聪明—如果停不满,它会把空车位的面积折叠掉,让已有的车停得更宽敞。

Q3: auto-fill 与 auto-fit 有什么区别?

基础梳理

auto-fill vs auto-fit 图解

专家视角深度剖析

很多人只能背下上面的表格,但实际更在意的是:auto-fill 创建的”幽灵轨道”在 Blink 底层到底是什么?为什么它们会占据空间? 在 Blink 的 GridLayoutAlgorithm 中,auto-fill 的逻辑是”尽可能多地创建隐式轨道”—它是一个刻板的机器,会按照 minmax(200px, 1fr) 的规则,在虚空中继续创建出一条条不可见的空白轨道来填满容器。这些轨道在物理上确实存在(占据了空间),只是里面没有元素而已。 而 auto-fit 的逻辑更聪明:它发现在布置完所有实际元素后,后续空余的空间其实没有元素可放,它会瞬间将那些空闲轨道的尺寸折叠崩塌为 0!随后,引擎把空出来的巨大可用空间重新打回资金池,交还给已有元素的 fr 去瓜分。

Q4: 经典面试题:1fr 为什么会被长文本撑爆?

1fr 为什么有时会失效? 当你写 1fr 时,它在底层等于 minmax(auto, 1fr)。这个致命的 auto 代表:这根铁轨的物理极小底线,不能小于其内部子元素内容的固有宽度(Min-Content)。一旦你放了一串极长的英文文本,这格的底线就被撑大到了几百像素,导致它抢夺了过量的空间,破坏了预期的 1:1 等分。
grid-template-areas 的陷阱: 如果用 grid-template-areas 命名区域,区域名称必须形成完整的矩形。如果区域不连续或形成”L”形,整个声明会被浏览器忽略。 关键区别:
当 Grid 格子内有长文本时,必须打破 auto 这个下限保护结界!将声明改为 minmax(0, 1fr),告诉渲染引擎:这根铁轨的物理底线可以被压缩到 0px。至于里面撑爆的文本?用 overflow: hidden 切掉即可。

在 Chrome 的 Blink 渲染引擎中,Grid 布局是一套重型、高度抽象的二维拓扑算法体系(详见 Blink 源码 src/core/layout/grid_layout_algorithm.cc):
在 Track Sizing Algorithm 中,fr 单位的计算逻辑是:先减去所有固定尺寸轨道和 gap,得到剩余空间(Free Space),然后按 fr 比例分配。详见 Blink 源码 src/core/layout/grid_layout_algorithm.cc 中的 DistributeFreeSpaceToFrTracks 函数。

十、及格回答 vs 满分回答

问题:“请问 Flex 布局和 Grid 布局的主要区别是什么?你在项目中是怎么选型的?”

及格回答(60-70分):
“Flex 是一维布局,只能控制一行或者一列;Grid 是二维布局,可以同时控制行和列。在做导航栏或者简单列表的时候我用 Flex,在做整个页面大框架或者九宫格抽奖页面的时候我用 Grid。”
问题出在:知道规则但不理解设计。 满分回答(90-100分):
Flex 和 Grid 的主要区别,是**“内容驱动的空间妥协”与”容器驱动的绝对统治”**的排版思想对立。Flexbox 是一维布局系统的王者——它的思想是”把元素像烤串一样串在主轴上”,换行后新行对上行无感知。Grid 是 CSS 历史上第一个纯粹的二维布局系统——你就像上帝一样俯视整个屏幕,直接用画笔在虚空中划定行与列的钢铁防线。Rachel Andrew 在 Grid by Example 中将这一思想总结为”Grid 让你从容器的维度思考布局,而非从内容出发”。Chris Coyier 在 CSS-Tricks 的《A Complete Guide to Grid》中则将其称为”CSS 布局的最终形态”。[1]
在 Blink 的 FlexLayoutAlgorithm 中,子元素就像充气气球,容器的最终形态往往受到内部内容尺寸的剧烈影响(由内向外)。而在 GridLayoutAlgorithm 中,父容器在第一阶段就会构建严密的拓扑轨道网络(Explicit Tracks),子元素只是被无情塞入预先划定好尺寸的物理牢笼之中(由外向内),哪怕内容极度膨胀溢出,网格的钢铁骨架也绝不轻易变形。Grid 还引入了颠覆性的 fr(Fraction)单位,它是在引擎物理减去了所有 gap 和固定 px 占位之后,专门用来公平瓜分”绝对剩余空间”的尚方宝剑。[2]
选型铁律是:对于组件级别的、流式的、需要随内容自适应折行的局部模块(如评论列表、Tag 标签堆叠),坚决使用 Flex。而对于宏观页面骨架结构(如后台管理面板 Dashboard)、以及必须绝对规整对齐的二维矩阵(如商品缩略图列表),坚决启用 Grid。特别是 repeat(auto-fill, minmax(X, 1fr)) 这行代码,它能在不需要一句 CSS 媒体查询的情况下,在底层引擎中实现全终端的响应式列数自动降级伸缩。Rachel Andrew 在 Grid by Example 中对此机制有权威的可视化对比:当子元素填不满容器时,auto-fill 会继续创建不可见的”幽灵轨道”,而 auto-fit 会将空闲轨道折叠为 0,把空间交还给已有元素。大漠在 W3cplus 上的 Grid 系列文章则为中文社区提供了系统性的理解路径。[3]

常见追问

答题要点: 不能只答”差不多”,必须点出”幽灵轨道”的关键差异。高分回答: “两者在容器塞满元素时表现一模一样,但当子元素极少,根本填不满整个容器时,裂变就发生了。auto-fill(自动填充):引擎是个刻板的机器,如果剩余空间足够,它会死板地继续在虚空中创建出一条条不可见的空白’幽灵轨道’来填满容器。auto-fit(自动适应):引擎是个机灵鬼,它发现在布置完所有实际元素后,后续空余的空间其实没有元素可放,它会瞬间将那些空闲轨道的尺寸折叠崩塌为 0!随后,引擎把空出来的巨大可用空间重新打回资金池,交还给已有元素的 fr 去瓜分。”
答题要点: 结合 Track Sizing Algorithm 解释 minmax(auto, 1fr) 的 auto 底线。高分回答: “当你写 1fr 时,它在底层等于 minmax(auto, 1fr)。这个致命的 auto 代表:这根铁轨的物理极小底线,不能小于其内部子元素内容的固有宽度(Min-Content)。一旦你放了一串极长的英文文本,这格的底线就被撑大到了几百像素。架构级修复方案是:必须打破 auto 这个下限保护结界!将声明改为 minmax(0, 1fr),告诉渲染引擎:这根铁轨的物理底线可以被残忍地压缩到 0px!至于里面撑爆的文本?用 overflow: hidden 切掉即可。”
答题要点: 必须分场景讨论!原生 Grid 不支持瀑布流,需要 Masonry 扩展。高分回答: “分两种情况: 1. 原生 Grid:原生 Grid 布局是基于严格的行列网格的,所有格子必须对齐,不支持瀑布流(即不同高度的元素交错排列)。 2. Masonry 扩展:Firefox 已经实验性支持了 grid-template-rows: masonry,可以让 Grid 实现瀑布流效果。但这个特性尚未进入 W3C 标准,Chromium 也尚未支持。在生产环境中,瀑布流通常使用 Masonry.js 等库实现,或者使用 CSS Columns(column-count)来做简单的多列布局。”
答题要点: 结合命名区域和区域分配的机制解释。高分回答: “grid-template-areas 在容器上定义命名区域,用字符串矩阵描述网格布局:
grid-area 在子元素上指定它应该占据哪个命名区域:
关键区别:grid-template-areas 定义区域形状,grid-area 分配元素到区域。区域名称必须形成完整的矩形,不能有空洞或 L 形。如果区域不连续,整个声明会被浏览器忽略。”
答题要点: 必须分场景讨论!subgrid 的适用场景和限制。高分回答: “subgrid 是 CSS Grid Level 2 引入的特性,允许子元素继承父 Grid 的轨道定义,而不是创建自己的 Grid。 解决的问题:当嵌套的 Grid 元素需要与外部 Grid 对齐时(如卡片列表中每张卡片的标题和内容需要对齐),普通 Grid 无法实现,因为嵌套 Grid 会创建自己的轨道系统。 使用方式:
兼容性:Chrome 117+、Firefox 71+、Safari 16+。目前支持度有限,但它是解决嵌套 Grid 对齐问题的标准方案。”
答题要点: 对比 auto-placement 与隐式轨道创建的内部逻辑。高分回答: “引擎的处理过程是冷酷的四步:1. 引擎首先构建你声明的 3 列显式轨道。2. 然后开启 Auto Placement(自动放置)的”扫雷模式”,按 grid-auto-flow 的方向(默认是 row),逐行扫描空隙。3. 当显式轨道填满后,引擎会动态创建隐式轨道(Implicit Grid)来兜底安置剩余元素。隐式轨道的尺寸由 grid-auto-rows 决定(默认是 auto,即由内容撑开)。4. 第 999 个元素会被放置在第 334 行(999 ÷ 3 = 333,余 0,即第 334 行第 3 列)。性能陷阱:如果 1000 个元素都需要创建隐式轨道,引擎的轨道计算开销会非常大。在真实项目中,应该使用虚拟滚动(Virtual Scrolling)来限制同时渲染的元素数量。”
答题要点: 对比默认的 row 流和 dense 流的差异。高分回答: “grid-auto-flow: dense 告诉引擎在自动放置元素时,可以”回溯填洞”——如果前面有空的格子,引擎会把后面的元素塞进去,即使这会打乱 DOM 顺序。 默认行为(row):引擎按行顺序放置元素,如果某个元素太大放不下当前行,会跳到下一行,留下空洞。 dense 行为:引擎会回溯前面的空洞,把后面的元素塞进去,保证没有空间浪费。 使用场景:
  1. 图片画廊:不同尺寸的图片需要紧密排列,不留空隙。
  2. 仪表盘:不同大小的卡片需要填满所有空间。 注意:dense 会打乱视觉顺序和 DOM 顺序的对应关系,可能影响无障碍访问(屏幕阅读器按 DOM 顺序朗读)。”
答题要点: 结合 auto-fill/auto-fit 和媒体查询解释。高分回答: “Grid 布局实现响应式的行列数调整有多种方式: 1. auto-fill/auto-fit:根据容器宽度自动计算列数。
2. 媒体查询:根据视口宽度手动设置列数。
3. 混合方案:使用 auto-fill 作为默认值,用媒体查询覆盖特定断点。 最佳实践:优先使用 auto-fill/auto-fit,减少媒体查询的使用。对于复杂的布局,可以结合媒体查询和 auto-fill 实现更精细的控制。”

📚 延伸阅读与引用参考