puppeteer是目前最可靠的html转pdf方案,基于chromium可真实还原css、字体、svg及js动态内容;需注意file://绝对路径、显式设置@font-face或启动参数、a4尺寸与页边距、printbackground:true等关键配置。

用 Puppeteer 生成 PDF 最可靠
浏览器环境渲染的 HTML 转 PDF,Puppeteer 是目前最稳定的选择。它基于 Chromium,能真实还原 CSS 布局、字体、SVG、甚至 JS 动态内容,不像纯服务端工具(如 weasyprint 或 wkhtmltopdf)容易丢样式或报错。
常见错误现象:Puppeteer.launch() 报 Failed to launch chrome;生成的 PDF 字体缺失或乱码;页眉页脚位置偏移。
- 确保系统已安装 Chromium 或让
Puppeteer自动下载:初始化时传{ headless: true, executablePath: null }(不指定路径即走自动下载) - 加载本地
index.html必须用file://协议,且路径需绝对化:await page.goto('file://' + require('path').resolve('./index.html')) - 若含中文,推荐在 HTML 中显式设置
@font-face并引用本地 TTF 文件,或启动时加参数:{ args: ['--font-render-hinting=none'] } - 页边距和 A4 尺寸需显式传入:
page.pdf({ format: 'A4', margin: { top: '20px', right: '15px', bottom: '20px', left: '15px' } })
避免 wkhtmltopdf 的兼容性陷阱
wkhtmltopdf 命令行简单,但底层依赖 QtWebkit,对现代 CSS(Flexbox/Grid)、ES6+ JS、@media print 支持差。很多用户卡在“PDF 空白”或“样式全崩”,其实不是配置问题,而是引擎不支持。
典型报错:QPainter::begin: Paint device returned engine == 0, type: 2;或 PDF 里只显示文字,无背景、无 border。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 不要依赖系统包管理器安装(如
apt install wkhtmltopdf),Ubuntu/Debian 默认版本太老,改用官网提供的静态二进制版 - 必须加
--enable-local-file-access才能读取本地 CSS/JS/图片,否则资源 404 -
--no-stop-slow-scripts和--javascript-delay 2000可缓解 JS 渲染不全,但治标不治本;复杂交互页面建议换Puppeteer
Node.js 脚本示例:三步跑通
以下是最小可运行脚本,保存为 html2pdf.js,直接 node html2pdf.js:
const puppeteer = require('puppeteer');
const fs = require('fs').promises;
(async () => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
// 注意:路径必须绝对,且带 file:// 前缀
await page.goto('file://' + (await fs.realpath('./index.html')), {
waitUntil: 'networkidle0' // 等资源加载完再截图
});
await page.pdf({
path: 'output.pdf',
format: 'A4',
printBackground: true // 否则 background-color/background-image 不生效
});
await browser.close();
})();
关键点:waitUntil: 'networkidle0' 比 'domcontentloaded' 更稳妥;printBackground: true 默认是 false,这点极易忽略。
字体与路径问题最容易被跳过
PDF 里中文字体发虚、英文变宋体、图标变成方块——90% 是字体没嵌入或路径不对。不是 HTML 写得有问题,而是生成环节没告诉 Chromium “去哪找字”。
- 本地开发时,Chrome 浏览器能显示字体 ≠ Puppeteer 能用同一套字体;Puppeteer 启动的是干净 Chromium 实例,不继承系统字体缓存
- 解决方案只有两个:① 在 CSS 中用
@font-face引入绝对路径的 TTF 文件(如url('/fonts/NotoSansCJK.ttc')),并确保该文件随index.html一起被file://加载;② 启动 Puppeteer 时指定系统字体目录:{ args: ['--font-render-hinting=none', '--font-cache-dir=/usr/share/fonts/'] }(Linux 路径) - 相对路径在
file://下极易失效,所有href/src/@font-face url()都建议转成file:///full/path/to/xxx格式预处理
真正卡住人的从来不是“怎么调 API”,而是路径协议、字体上下文、渲染时机这三个点交叉出问题。多打一行 console.log(page.url()) 看实际加载地址,比反复改 CSS 有用得多。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










