← 首页 / 🟩 CSS Grid · 二维布局与轨道模型 待审核 8 页

🟩 CSS Grid · 二维布局与轨道模型

Flexbox 沿单轴排布,Grid 则把容器先划成二维轨道网格,再把项放进由网格线围成的单元。本系列从轨道的定义讲起——fr 如何分配剩余空间、minmax() / repeat() / auto-fill 怎样组合出响应式列;再到放置(基于网格线、span、auto-placement 与 dense)、区域命名(grid-template-areas 字符画)、两轴对齐(注意 Grid 的 justify-* 管行内轴、与 Flex 的轴映射不同);最后两块进阶能力——subgrid 让嵌套网格继承父轨道、display: contents 让包裹层「消失」,它们正是「跨容器对齐到同一组列线」这一经典需求的两种解。每页都用真实 getComputedStyle / getBoundingClientRect 实测呈现引擎的实际行为。

系列脉络:

先把网格画出来——轨道与 fr(minmax / repeat / auto-fill vs auto-fit)→ 往格子里放项:基于网格线的放置(span / 负向线号 / grid-auto-flow: dense)→ 用 grid-template-areas把布局画成字符画 → 理清 Grid 的两轴对齐(行内轴 justify-* vs 块轴 align-*,与 Flex 相反)→ 看 grid-item 如何脱离源码顺序:order / z-indexreading-flow(视觉序与可达性)→ 进阶:subgrid让嵌套网格对齐父轨道、display: contents让中间层穿透 → 收束于一个实战:同一份「三列对齐列表」的四种实现对照。 tracks · 轨道

定义轨道:fr、minmax、repeat 与 auto-fill / auto-fit

Grid 的地基是轨道:grid-template-columns 列出每条列轨的尺寸。fr 是「剩余空间的份额」——先扣掉固定轨道与 gap,再按份额瓜分余量;minmax(min, max) 给轨道一个伸缩区间;repeat(auto-fill, minmax(120px, 1fr)) 据容器宽自动决定列数。拖宽度 / 改份额,用 getComputedStyle 读回引擎解析后的 px,看 fr 究竟分到多少、auto-fillauto-fit 在空轨上的差别。

placement · 放置

放置:基于网格线、span 与 auto-placement

网格线从 1 开始编号(也可从尾部用 -1 负向计数)。grid-column: 1 / 3 让项从 1 号线跨到 3 号线、grid-row: 2 / span 2 跨两行。未显式定位的项由 auto-placement 算法沿 grid-auto-flow 方向逐格填入;dense 会回填前面被跳过的空洞(代价是打乱 DOM 顺序)。拖动定位、切 row / column / dense,观察空洞如何产生与回填,以及溢出显式网格时隐式轨道怎样长出来。

areas · 区域命名

grid-template-areas:把布局画成字符画

grid-template-areas字符串矩阵给单元命名,项再用 grid-area: main 落位——布局结构在 CSS 里一眼可读,改版式只需重排字符串。每个命名区会隐式生成 <name>-start / <name>-end 命名线;. 表示留空单元;同名格必须连成矩形否则整条声明失效。编辑模板字符串实时重排经典「holy-grail」版式,并演示窄屏下重画字符串即完成响应式重排。

alignment · 两轴对齐

两轴对齐:justify- 管行内轴、align- 管块轴

Grid 的对齐沿两条轴展开:justify-*行内轴(默认横向)、align-*块轴(默认纵向)——与 Flex 按主 / 交叉轴的记法不同,初学常混。*-items / *-self 把项在各自单元内对齐(这里 justify-self 生效,与 Flex 不同);*-content轨道整体小于容器时分配剩余空间;place-* 是两轴简写。切换各值实时看项在单元内的位置并回显 computed 值。

reading-flow · 序与可达性

视觉顺序与源码顺序:order、z-index 与 reading-flow

Grid 把项从 DOM 顺序里解放出来:order 重排视觉而不动源码顺序、项可重叠到同一组单元(此时直接用 z-index 决定堆叠,无需 position)。代价是键盘 Tab 焦点屏幕阅读器朗读仍沿 DOM 走,与视觉脱节。reading-flow: grid-rows(及对单项微调的 reading-order)把顺序焦点导航拨回视觉顺序。用 getBoundingClientRect / elementFromPoint 与真实 Tab 轨迹实测三者。

subgrid · 继承父轨道

subgrid:让嵌套网格对齐到父级的同一组线

嵌套网格默认自成一套轨道,于是并排的多张卡片内部(标题 / 正文 / 按钮)各排各的、跨卡对不齐。grid-template-columns: subgrid 让子网格不再自定义轨道,而是采用父网格在该跨度内的轨道线——所有卡片的对应行因此落在同一组网格线上、天然对齐。切 subgrid ↔ 独立轨道对照跨卡基线;并说明它解决的正是「subgrid 之前只能靠固定轨道凑」的老问题。

display: contents · 穿透

display: contents:让包裹层消失,子项直上父网格

Grid 只对直接子元素建立网格项。当容器与真正内容之间隔着一层语义包裹(列表 <li>、组件根)时,这层会独占一个单元、把内容「闷」在里面。display: contents 让这层自身不生成盒子、其子元素上移直接成为父网格的项,从而用扁平 grid 对齐多行结构(subgrid 之前的常用替代)。实测切 blockcontents 看子项如何进入父轨道;并讲清代价(自身 border / background 失效)、a11y 历史坑、对 replaced 元素无效、vs display: none

实战 · 三列对齐列表

同一份「配额进度列表」的四种实现对照

一个常见诉求:左列名称(随内容自适应)、中列进度条(占满余量)、右列数值(随内容自适应),且多行之间三列严格对齐。本页把它用四种方式实现并排对照:经典 display: tabletable-cell、表格 + width 技巧、grid + li { display: contents }grid + subgrid,逐一拆解各自如何「让三列对齐」、各自的取舍与适用边界。

一条贯穿全系列的主线。

「让分散在多行 / 多个子树里的内容,对齐到同一组列线」是 Grid 最常被需要、也最容易出错的能力。从早年的 display: table,到 grid + display: contents 穿透包裹层,再到 subgrid 直接继承父轨道——解法一路演进,核心始终是谁来定义那组共享的轨道线、谁去采用它。读完subgriddisplay: contents实战页,这条线就完整了。

🔗 相关链接

📐 规范 / 文档

🎨 实例与文章(本系列灵感来源)