如果说 Flexbox 解决了一维排列,Grid 解决的则是二维网格:卡片墙、报表矩阵、价目表、日程表,用 Grid 几行代码就能排布整齐,列宽自动均分、跨行跨列随意控制,这是传统表格布局和绝对定位难以企及的开发效率。dompdf.js 对 Grid 布局提供支持,grid-template-columns、grid-template-rows、gap、grid-column、grid-row 等属性都能按标准 CSS 渲染,让复杂版式的前端 PDF 开发变得前所未有的简单,网页里排好的网格可以直接用于导出。本文从 Grid 的基本概念讲起,覆盖容器属性与项目放置语法,配合真实代码示例演示报表网格与卡片网格的写法,并讲解 Grid 与分页的配合、与 Flexbox 的混用技巧,最后给出常见问题排查与降级方案,帮助你用好这个强大的二维布局工具,把复杂的 PDF 版式从苦力活变成配置活。文中示例均可在本地直接运行验证,代码注释解释了关键语法,照着实践即可快速上手。
Grid 布局的本质是在容器内建立网格线,由网格线划分出轨道(行与列),项目放置在轨道交叉形成的单元格中。dompdf.js 按标准盒模型计算网格轨道尺寸,display: grid 的容器会进入网格布局模式,子元素成为网格项目。
理解网格线的编号规则很重要:网格线从 1 开始编号,1 号线在容器起始边缘;grid-column: 1 / 3 表示项目从第 1 条列线跨越到第 3 条列线,占据两列。负号编号从末尾倒数,grid-column: 1 / -1 表示从开头到结尾,是跨满整行的常用写法。
与 Flexbox 的一维思维不同,Grid 需要同时考虑行与列两个维度:行轨道由 grid-template-rows 定义,列轨道由 grid-template-columns 定义,两者可以独立设置固定值、百分比与 fr 弹性单位,组合出千变万化的网格结构。
网格线与轨道的关系也可以从布局意图理解:定义轨道其实是定义网格线的位置,项目通过网格线编号描述落点;这种声明式写法让版式意图一目了然,相比手写坐标,改版时只需调整轨道定义,维护成本大幅降低。
fr 单位是 Grid 的核心特性:1fr 表示一份剩余空间,repeat(4, 1fr) 就是四等分;与百分比相比,fr 会自动处理内容溢出与空间分配,不会因为内容宽度变化而破坏比例,是响应式网格的首选单位。
grid-template-columns 定义列轨道:repeat(3, 1fr) 表示三列等分,1fr 是弹性单位,按剩余空间比例分配;固定值加弹性的组合(如 200px 1fr 2fr)可以做出侧栏加主区的经典布局,与浏览器行为一致。
gap 属性同时设置行列间距,取代旧的 grid-gap,是网格布局中最常用的间距写法;grid-auto-rows 定义隐式行的尺寸,配合 minmax(80px, auto) 可以控制自动生成的行高范围,适合内容高度不固定的列表型网格。
grid-auto-flow 控制项目自动放置的方向:row 默认按行填充,column 按列填充;dense 值允许回填空洞,适合项目尺寸不一的场景。理解自动放置规则,可以避免项目落点与预期不符的困惑,排查布局异常时先检查这一属性。
minmax() 函数让轨道尺寸有了弹性区间:minmax(100px, 1fr) 表示列宽至少 100px、最多占满剩余空间,适合内容最短宽度有要求的长文本列;auto 关键字则让轨道按内容自适应,灵活组合可以覆盖绝大多数布局需求。
grid-auto-rows 与 grid-auto-columns 控制隐式轨道的尺寸,显式轨道之外的自动生成行列都受它们约束;模板中固定隐式行高(如 grid-auto-rows: minmax(40px, auto))可以让自动扩展的列表保持整齐,避免行高忽高忽低。
项目可以显式指定落点:grid-column: 1 / 3 跨两列,grid-row: 1 / 3 跨两行,也可以使用 span 关键字:grid-column: span 2 表示跨越两列,写法更直观,不用数网格线编号,适合在模板里快速调整。
grid-area 可以合并行列定义:grid-area: 1 / 1 / 3 / 3 表示行起止与列起止四个值,一次指定;配合 grid-template-areas 命名区域(如 header、sidebar、main、footer),可以用 ASCII 图形直接描述版式,可读性极高,适合结构固定的文档模板。
跨行跨列是 Grid 相对表格的核心优势:表格无法让单元格随意跨越行列而不破坏结构,Grid 则可以任意组合,报表中的合并单元格、卡片墙中的特色大卡、日程表中的跨时段事件,都能用几行声明完成,维护成本远低于传统方案。
span 关键字比数字编号更不易出错:grid-column: span 2 只声明跨越数量,不需要数网格线,模板调整时改动更小;配合 grid-row: span 2 可以实现区域卡片,代码可读性也更高,推荐在模板中优先使用。
命名区域(grid-template-areas)适合结构固定的文档:用 ASCII 图形描述版式,改版时直接调整图形布局即可,代码意图一目了然;注意命名区域要求每个单元格都有名字或用点号占位,语法严格但回报很高。
import { DomPDF } from 'dompdf.js';
const html = `
<style>
.report {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: 1px;
background-color: #b8c2cc; /* 缝隙即网格线 */
border: 1px solid #b8c2cc;
}
.report > div {
background-color: #fff;
padding: 10px;
}
.report .head {
background-color: #2c3e50;
color: #fff;
font-weight: bold;
}
.report .total {
grid-column: 1 / -1; /* 跨满整行 */
text-align: right;
font-weight: bold;
}
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-top: 20px;
}
.cards .feature {
grid-column: span 2; /* 特色卡跨两列 */
background-color: #eaf2fb;
}
</style>
<div class='report'>
<div class='head'>项目</div><div class='head'>数量</div><div class='head'>金额</div>
<div>机械键盘</div><div>1</div><div>¥ 399</div>
<div>显示器</div><div>2</div><div>¥ 3,998</div>
<div class='total'>合计 ¥ 4,397</div>
</div>
<div class='cards'>
<div class='feature'>推荐商品(跨两列)</div>
<div>配件专区</div>
<div>服务保障</div>
</div>`;
const pdf = new DomPDF({ format: 'A4', margin: '20mm' });
pdf.addPage(html, { format: 'A4' });
pdf.save('grid-demo.pdf');
Grid 负责整体骨架,Flexbox 负责局部细节,是前端布局的黄金组合:Grid 搭建报表的行列框架,单元格内部用 flex 对齐图标与文字;这种分层思路在 PDF 模板中同样适用,结构清晰且易于维护,推荐作为复杂版式的首选方案。
网格跨页时,dompdf.js 会按行轨道寻找分页点,行高固定的网格分页更整齐;建议给重复行设置稳定的行高(固定值或 minmax 下限),避免行高随内容波动导致分页位置不稳定,也方便控制每页显示的行数。
跨行跨列的项目在分页边界处可能出现内容截断,建议把跨多行的合并单元格放在数据区中间,避开页边界;长报表建议按页拆分数据源,每页独立构建网格,而不是依赖引擎自动拆分,输出效果最可控。
Grid 与分页的配合还有一个细节:网格容器跨页时,容器自身的边框与背景同样按页拆分,如果希望每页都有完整边框,可以把边框放到每个单元格上,用 gap 配合背景色模拟网格线,分页后依然整齐。
每页行数控制可以通过固定行高实现:先计算内容区高度,除以单行行高得到每页行数,再按行数拆分数据源;这种按页构建网格的方式在报表模板中非常实用,输出页数可精确预期,也方便添加每页小计。
Q: 网格列宽与预期不符?A: 检查是否混用了固定值与百分比导致空间溢出,fr 单位会自动分配剩余空间,与固定值混用时先分配固定值;溢出时给容器设置 min-width: 0 或调整轨道定义,即可恢复预期分布。
Q: 项目没有落在预期的单元格?A: 检查 grid-auto-flow 与隐式轨道:项目数量超过显式定义的行列数时,会自动生成隐式轨道,尺寸由 grid-auto-rows 或 grid-auto-columns 控制;显式指定落点可以完全避免歧义。
Q: Grid 与分页配合时内容被截断?A: 给重复单元设置稳定行高,并检查跨行项目是否跨越了分页边界;把跨页风险高的内容放在数据区中部,或按页拆分数据源,分页表现即可稳定。
降级方案:老旧渲染环境对 Grid 支持不完整时,可以用表格布局还原等宽网格,用 flex 加百分比还原弹性网格;功能等价但模板代码更长,建议仅在确需兼容的场景使用,新模板优先采用 Grid。
Grid 的兼容性检查同样重要:模板上线前用目标浏览器与 dompdf.js 各渲染一次对比,重点核对轨道尺寸、跨列落点与间距;发现差异时优先检查是否混用了旧语法(如 grid-gap),统一到新语法后通常即可解决。
如果遇到网格内项目内容溢出,检查轨道是否允许收缩:1fr 轨道默认可以收缩,内容过长时会被压缩;给轨道设置 minmax 下限或给项目设置 overflow 处理,可以避免内容重叠,输出更干净。
下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:
这是由 dompdf.js 渲染的示例 PDF 内容。