Chrome无头模式导出PDF最稳,支持JS执行、CSS打印媒体、Flex/Grid布局及中文字体;需用file://协议、避免中文路径,Puppeteer导出须设format:'A4'、printBackground:true、waitUntil:'networkidle0'。
用 chrome 命令行直接导出 PDF 最稳
本地 html 转 pdf,最可靠的方式不是靠 js 库,而是调用 chrome 自带的无头模式。它渲染准确、支持 css @media print、能处理现代布局(flex/grid)、也兼容字体和中文。
常见错误是直接用 pdfkit 或 weasyprint 硬转 —— 它们不执行 JS、不加载远程字体、对 position: sticky 或 transform 渲染经常错位。
实操建议:
- 确保系统已安装 Chrome 或 Chromium(macOS 可用
brew install chromium;Linux 用包管理器;Windows 下路径注意空格,推荐用短路径如C:\chrome\chrome.exe) - 命令示例:
chrome --headless --disable-gpu --print-to-pdf="output.pdf" "file:///path/to/index.html"
- 加
--margin-top=0 --margin-bottom=0 --margin-left=0 --margin-right=0去白边;加--print-to-pdf-no-header去页眉页脚 - 如果 HTML 依赖本地 JS/CSS,务必用
file://协议,且路径不能含中文或空格(否则 Chrome 会静默失败)
page.pdf() 在 Puppeteer 里怎么设好纸张和缩放
Puppeteer 是自动化场景首选,但默认导出常出现内容被截断、字体糊、或 A4 宽度撑不满——问题多出在纸张尺寸没对齐 viewport,或没等 JS 渲染完就导出。
关键参数必须显式指定:
立即学习“前端免费学习笔记(深入)”;
-
format: 'A4'比width/height更稳妥(避免单位换算错误) - 加
printBackground: true,否则 CSSbackground-color不显示 - 用
waitUntil: 'networkidle0'替代'load',确保异步资源(图标、字体、数据请求)全部完成 - 若页面有动态高度(比如展开菜单),导出前先执行
await page.evaluate(() => document.body.style.height = 'auto')
为什么 wkhtmltopdf 在 macOS/Linux 上容易崩
它底层用 QtWebkit,早已停止维护,不支持 ES6+、CSS variables、grid,遇到 IntersectionObserver 或 Web Font 就卡死或空白。
典型报错:QFont::setPixelSize: Pixel size 或直接无输出。
除非你明确要支持 CentOS 6 这类老系统,否则别碰。替代方案:
- macOS:改用
chromium --headless(比wkhtmltopdf快 2–3 倍,内存占用低) - CI 环境(如 GitHub Actions):用官方
puppeteerDocker 镜像,自带 Chromium,免配置 - 真要保
wkhtmltopdf,必须降级到 0.12.6,并禁用所有现代 CSS 特性
导出 PDF 后中文显示为方块?字体路径是关键
不是缺字体,是 Chrome 找不到它。HTML 中用 @font-face 加载的本地字体(如 src: url('./fonts/msyh.ttc')),在 file:// 协议下会被浏览器拦截(CORS + file 协议限制)。
解决路径只有两条:
- 把字体转成 base64 内联进 CSS(适合小字体文件,
msyh.ttc太大,不推荐) - 起一个本地 HTTP 服务(哪怕一行
python3 -m http.server 8000),然后用http://localhost:8000/index.html访问再导出 —— 这样字体加载不受限 - Linux 服务器上记得装中文字体包,如 Ubuntu:
sudo apt-get install fonts-wqy-zenhei,否则即使路径对,Chrome 也 fallback 到无中文的默认字体
最容易被忽略的是:PDF 导出时不会报字体加载失败,只会静默用替代字体,所以得打开生成的 PDF 逐页确认中文是否正常显示。











