← dompdf.js Studio

PDF 中文字体配置指南:dompdf.js 零配置方案

前端项目里生成中文 PDF,最头疼的往往是字体问题:不是乱码,就是满屏豆腐块,要么得在服务器上安装字体,要么把几十 MB 的字体文件打进前端资源,加载慢、占带宽、拖累首屏。jsPDF 这类库还需要手动引入 TTF 并注册字体名,步骤繁琐,每个项目都要重新来一遍。而 dompdf.js 直接内置了思源黑体(Source Han Sans SC),开箱即用,无需任何字体配置,一行代码就能导出文字清晰、可搜索、缩放不失真的中文 PDF。无论你是在做发票、合同、报表还是简历导出,掌握这套方案都能少踩很多坑。本文从乱码原理讲起,逐步介绍 dompdf.js 的字体方案、代码示例、样式细节与问题排查,帮你一次性搞定前端中文 PDF 生成,少走弯路。

中文 PDF 为什么容易乱码

中文乱码的根源在于字体缺失。PDF 文件本身不携带操作系统字体,生成引擎在渲染时如果找不到可用的中文字体,就会用占位符代替,表现为方块、问号或整段空白。同样的 HTML 在 Chrome 里显示正常,导出成 PDF 却变成乱码,正是因为 PDF 渲染引擎拿不到浏览器页面里加载的字体资源,两者使用的字体环境完全不同。

团队通常会在三种解决方案里选一个,而每种都有隐藏成本。服务器方案要在后端安装中文字体包,依赖运维、拖慢每次渲染;打包方案把字体文件塞进前端资源,动辄几十 MB,首屏加载被拖累;转图片方案把文字变成像素,彻底失去选中与搜索能力,文件体积还暴涨,打印质量也下降。

还有一个更隐蔽的问题:即使字体装好了,很多工具输出的其实是位图 PDF,文字被栅格化成像素,放大后边缘发虚,打印效果也差。真正专业的做法是输出矢量文字,把字形轮廓写进 PDF,任意缩放都保持锐利。这个区别比多数教程强调的重要得多,直接决定文档的可用性与专业度,也影响后续的搜索、复制与无障碍阅读。

另外要注意字符编码的连环问题:数据库、接口、模板三个环节只要有一个不是 UTF-8,中文内容在进入渲染引擎前就已经损坏,导出的 PDF 自然跟着出错。排查乱码时建议先在前端打印 HTML 字符串确认内容完整,再检查渲染环节,能快速缩小问题范围。

dompdf.js 的零配置方案

dompdf.js 在发布包中直接内置了思源黑体(Source Han Sans SC),这是 Adobe 与 Google 联合开源的思源黑体简体中文版,覆盖 GB2312 常用汉字与大量生僻字,商用免费,字形质量高,是目前前端生成中文 PDF 最省心的默认字体之一,也是许多中文字体方案的首选。

因为字体随库打包并默认启用,你不需要做任何字体配置:不需要 @font-face,不需要 addFont,不需要额外加载字体文件,更不需要处理字体子集化。new DomPDF() 之后直接 addPage 传入中文内容即可,从写下代码到下载第一份中文 PDF 通常不超过一分钟,这就是零配置设计的价值所在,也意味着团队成员不需要额外学习字体知识。

渲染内核采用 Rust+WASM,字形直接以矢量路径写入 PDF,因此输出文件小、文字可搜索、可复制、可选中,任意缩放与打印都保持锐利。这个质量水准与无头浏览器等重型方案相当,但完全发生在浏览器内,不需要任何服务器资源,部署与维护成本为零,非常适合前端团队独立交付。

零配置也带来一个额外好处:团队协作时不需要同步字体文件或约定字体路径,任何成员拉取代码就能直接生成中文 PDF,CI 构建也不会因为字体缺失而失败,交付链路更顺畅。

代码示例:导出中文 PDF

import { DomPDF } from 'dompdf.js';

const reportHTML = `
  <style>@page { margin: 20mm; }</style>
  <h1>月度销售报告</h1>
  <p>2026 年 8 月,华东大区销售额同比增长 23.6%,</p>
  <p>其中线上渠道贡献了 61.4% 的增量。</p>
  <table style="width:100%;border-collapse:collapse">
    <tr>
      <th style="border:1px solid #333;padding:8px">区域</th>
      <th style="border:1px solid #333;padding:8px">销售额</th>
    </tr>
    <tr>
      <td style="border:1px solid #333;padding:8px">华东</td>
      <td style="border:1px solid #333;padding:8px">¥ 1,286,500</td>
    </tr>
  </table>`;

// 中文内容直接放入 HTML 字符串即可,无需任何字体注册
// 表格、加粗、对齐等样式由引擎自动处理
const pdf = new DomPDF();
pdf.addPage(reportHTML, { format: 'A4', margin: '20mm' });
pdf.save('report.pdf');

字体细节:字号、粗细与样式

内置字体默认支持常规与粗体两种字重,设置 font-weight: bold 或使用 <b> 标签即可得到加粗效果,无需额外加载粗体字体文件,也不必担心粗细混排时体积翻倍或出现假粗体毛边。生成标题加粗、金额强调这类常见需求,一行 CSS 就能搞定,样式与网页端保持一致。

字号通过 font-size 控制,px 与 pt 单位都支持。正文建议 12-14px(约 9-10.5pt),标题按层级逐级放大;行高 line-height 推荐 1.5-1.8,因为汉字在 em 框中位置偏高,合适的行高能让中文段落明显更舒展、更易读,尤其是大段说明文字,阅读体验差异非常直观。

需要与其他字体混排时(比如数字使用等宽字体对齐表格),正常设置 font-family 即可,内置思源黑体始终作为兜底可用,任何字体缺失都不会导致整页崩溃。中英文混排时注意两者之间的字距,必要时用 letter-spacing 微调,整体观感会更精致,也更接近设计稿的效果。

常见问题与排查

Q: 导出的中文变成方块?A: 先确认 dompdf.js 版本是否过旧,早期版本可能未内置中文字体;升级到最新版并清空构建缓存重新打包即可。若问题依旧,检查 HTML 是否全程使用 UTF-8 编码,字符集不一致也会导致渲染异常。

Q: 生僻字显示不出来?A: 思源黑体覆盖数万汉字,绝大多数生僻字都能正常渲染;极少数扩展区字符可能缺失,建议替换为常见同义字或改写表述,避免文档出现空洞,影响阅读与检索。

Q: 自定义字体怎么用?A: 目前最稳妥的方式是保持默认内置字体,通过 CSS 控制样式;若业务强依赖特殊字体,请查阅官方文档的字体扩展接口,按官方 API 接入,不要自行魔改,以免引入不稳定因素。

Q: 为什么 PDF 里的中文看起来比网页上小?A: 这是 px 与 pt 的换算问题,1pt 约等于 1.333px。CSS 中统一使用一套单位,页面预览与 PDF 输出就能保持一致,不会出现字体忽大忽小的困扰,也方便设计走查。

Q: 同一份模板有时正常有时乱码?A: 多半是动态数据源编码不一致,比如部分记录来自旧系统用了 GBK。统一在数据入口做一次编码转换,把内容规范成 UTF-8 再进模板,问题就能根治。

对比:其他方案的中文字体有多麻烦

jsPDF 自带 Helvetica 等标准西文字体,不含任何中文字形,必须调用 addFileToVFS 与 addFont 注册 TTF 字体文件,还要处理字体子集化与体积控制,配置繁琐且每个项目都要从头再来一遍,新手极易在此卡住。

html2pdf.js 通过 html2canvas 截图生成位图,中文字体依赖页面本身已加载的字体,字体未就绪就会出现空白或错位,而且输出文字不可选中、放大模糊,打印效果也远不如矢量方案,中文场景的体验短板明显。

服务端方案如 Puppeteer 需要运维在服务器安装中文字体包(如 fonts-noto-cjk),部署成本高、响应慢,还要承担服务器资源开销。对比之下,dompdf.js 把字体问题彻底内置化,是前端中文 PDF 方案里配置成本最低、输出质量最高的选择,值得优先评估。

⚡ 现场演示(点击生成 PDF)

下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:

Hello from dompdf.js!

这是由 dompdf.js 渲染的示例 PDF 内容。