HTML → PDF 转换器,免费
将 HTML 代码转换为 PDF,支持完整自定义。添加 logo、美化文档并生成专业 PDF · 全部在您的浏览器中完成。
预览将显示在此处…
关于 HTML → PDF 转换
PDF 起源于 1991 年 John Warnock 在 Adobe 内部启动的「Camelot」项目,一份内部提案,目的是创造一种「通用文件格式,能从任何应用程序里捕获文档、把这些文档的电子版送到任何地方、并在任何机器上查看和打印」。Warnock 是 Adobe 的联合创始人,也是 PostScript(与 Charles Geschke 合作发明)的发明者;Camelot 的目标是把 PostScript 的「打印保真」承诺延伸到屏幕上。Acrobat 1.0 与 PDF 1.0 于 1993 年 6 月发布,第一版商用 Acrobat reader 售价 50 美元。PDF 在十五年里一直是 Adobe 控制下的私有格式;Adobe 于 2008 年将规范交给 ISO 成为 ISO 32000-1:2008(PDF 1.7 作为开放标准发布);大版 PDF 2.0(ISO 32000-2)在 2017 年到来,修订持续到 2020 年。Adobe 在 2023 年 4 月放弃了其剩余的专利权,使 PDF 在全球范围内完全无专利负担。PDF 现已是通用的「可移植文档格式」,每一个操作系统都原生读它,每一台打印机都懂它,每一个法律体系都承认它。整座大厦建立在 PostScript 风格的固定位置布局之上:PDF 页面上的每一个元素都有绝对的 (x, y) 坐标,与页面坐标系的基线对齐;文字以「字体 + 字形索引」编码,图形则以路径指令表达。
HTML 与 PDF 在根本上不匹配,这就是 HTML→PDF 转换比看起来更难的原因。HTML 是基于回流(reflow)的(内容随 viewport 适配,缩放时段落重新换行,用户缩放时布局会变。PDF 是固定布局)每个元素都被绝对定位,页面边界是显式的,根本不会发生回流。从一种转换到另一种,会被迫做一系列棘手的决定:怎么切分长页面、嵌入字体存在哪里、矢量图形如何保留、链接还能否点击。多数问题没有客观正确的答案,正确的行为取决于你的用例。
两种 JavaScript 实现路线:栅格 vs 矢量
基于浏览器的 HTML→PDF 转换有两种架构。html2pdf.js(Erik Koopmans,本工具所用)封装了两个底层库,html2canvas(从 DOM 读取布局并重绘,把 HTML 元素渲染为 canvas 图像)和 jsPDF(用原语构建 PDF)。流水线是:HTML → canvas 图像 → 把图像嵌入 PDF。结果是 像素级精确(你在预览里看到的就是你拿到的 PDF)但 只是栅格:PDF 里的「文字」是图像,不是可选择的文本。无法在 PDF 里搜索词、无法复制粘贴、屏幕阅读器读不到它。对于报表、证书、发票、一次性文档而言这能接受;对于需要可搜索或无障碍的文档来说,这是一个明显的限制。另一种架构是直接使用 jsPDF 的文本渲染原语(doc.text()、doc.line()、doc.image()),从零搭起一份带可选文本与矢量图形的 PDF。代价是你要为想要支持的每一种 HTML 元素都写转换代码(但产出的是一份「真正的」可搜索、可访问的 PDF。取舍:html2pdf.js 一行代码就能跑;直接走 jsPDF 是一个相当可观的工程项目。本工具优先选择易用(html2pdf.js)而非文本可选)在判断输出是否满足需求时请记得这点。
服务端替代品,当浏览器端不够用时
wkhtmltopdf 曾是长期主流的开源 HTML→PDF 命令行工具,一个基于 WebKit 的渲染器,在服务器上把 HTML 转成 PDF。它被用于无数 CI 流水线、企业应用和 PDF 生成服务。wkhtmltopdf 项目已于 2023 年归档(GitHub 仓库现在是只读);不再建议把它选为新应用的方案,尽管它已经生成了数十亿份 PDF。Puppeteer(Google,2017 年起的 headless Chrome)是当代服务端 HTML→PDF 的事实标准。Puppeteer 的 page.pdf() 用的是 Chromium 完整的 PDF 生成流水线,可选文本、嵌入字体、矢量图、超链接全都能正确工作,因为 Chromium 有一个真正的 PDF 后端。Playwright(Microsoft,2020)是跨浏览器的对应物(Chromium、Firefox、WebKit),具备同样的 PDF 生成能力。Prince(商业软件,每台服务器 495 美元)是同类中最强的 CSS Paged Media 实现,支持多栏、运行页眉/页脚、命名页、脚注、OpenType 功能。WeasyPrint(开源,Python)是带类似能力的跨平台替代。Paged.js 是一个 polyfill,把 CSS Paged Media 的能力带到浏览器端 PDF 生成里。浏览器自带的「另存为 PDF」(文件 → 打印 → 另存为 PDF)是其中最便宜的方案,免费、已装好、对 CSS Paged Media 支持得相当不错,产出的也是可选文本的 PDF。对于一次性转换,这通常才是正确答案,根本不需要第三方工具。
CSS Paged Media,真正的「从 CSS 打印」是怎样工作的
W3C 的 CSS Paged Media Module 定义了一组专门为分页输出设计的 CSS 特性:@page 规则用来控制页面尺寸、页边距与方向;@page :left / @page :right 用来为书本式的左右两类页面设置不对称页边距;@page :first 用于专门处理首页;margin boxes(@top-center、@bottom-right 等)用来放置运行页眉与页脚;page-break-before / page-break-after / page-break-inside(现代写法 break-before: page / break-after: page / break-inside: avoid)用来控制页面何处分页;orphans 与 widows 用于段落分页控制。各浏览器的打印流水线里 CSS Paged Media 的实现程度参差不齐。Prince 与 WeasyPrint 实现了完整规范;Chrome 的 page.pdf() 覆盖了大部分;html2pdf.js(本工具)支持基础的 page-break-* 规则,但跳过了较精细的 margin-box 与命名页特性。对需要书本级质量的文档(标题页、章节起始、运行页眉、脚注),请用 Prince 或 WeasyPrint;对于典型的「把这份报告另存为 PDF」的场景,html2pdf.js 就够了。
常见用途:
- 发票与收据。最常见的业务场景,一份结构化 HTML 模板用订单数据填充后导出为 PDF,再邮件发送或存档。「文本不可选」的限制在这里很少要紧,因为收件人不需要在单张发票里搜索内容。
- 报表与文档。季度业务报表、项目交付物、内部状态文档,由模板系统生成、导出为 PDF 用于分发。
- 证书。课程结业证书、会议出席证书、成就徽章,通常是一张带 HTML/CSS 样式的页面,作为一次性 PDF 导出。
- 简历与 CV。候选人在网页模板上构建自己的简历(Notion 导出、自制构建器)并导出为 PDF 投递。这里「文本可选」很重要,因为招聘软件(ATS)经常会从简历 PDF 里抽取关键词。
- 门票与确认单。演唱会票、登机牌、酒店确认单,从网页预订流程导出,用于离线保存或打印。
- 网页内容归档。把一篇文章、博客或文档页面保存为固定格式 PDF,用于离线参考或长期保存。
- 邮件转 PDF。把 HTML 邮件(通讯、公告)转成 PDF,用于转发或合规归档。
诚实的边界:这个工具做什么、不做什么
本工具使用 html2pdf.js v0.10.1(捆绑了 html2canvas + jsPDF 的构建版本)在你的浏览器里渲染 HTML 并产出 PDF 下载。所生成的 PDF 对预览像素级精确(所见即所得)但文字被渲染为栅格图像,不是可选择的文本。它支持 A4、Letter、A3、A5 页面尺寸,纵向与横向,可配置的边距、自定义文件名以及基础 CSS page-break-* 规则用于分页控制。本工具不做、当你需要它时该转而使用其他方案的功能:PDF 中可选/可搜索的文本(请用服务端 Puppeteer,或浏览器自带的「另存为 PDF」);书本级排版带运行页眉、页脚、命名页、脚注(请用服务端 Prince 或 WeasyPrint);已渲染 HTML 中的 JavaScript 执行(转换器把 HTML 走一遍 html2canvas,它不会执行已渲染内容中的脚本);动画内容(PDF 是静态的);依赖打印上下文的媒体查询(渲染发生在 screen 上下文)。对于日常的「把这份 HTML 出一份 PDF」需求,html2pdf.js 够用;对于需要真实 PDF 文本和无障碍输出的生产级流水线,服务端 Puppeteer 才是当代标准。
隐私:为什么在这里也要「只在浏览器里跑」
PDF 生成是一门常见的 SaaS 云生意,DocRaptor、PDFShift、PDFCrowd、API2PDF 等服务按生成数量收费,往往是因为他们在服务器集群上跑 headless Puppeteer,并吸收 GPU 加速渲染的成本。代价是你提交给那些服务的 HTML 是在它们的基础设施里处理的:发票里有客户信息,报表里有业务数据,证书里有姓名,简历里什么都有。无论你生成什么,第三方服务都看得到。本工具完全在你的浏览器里通过 html2pdf.js 运行,点 Generate 时打开 DevTools 的 Network 选项卡验证(唯一的出站请求是从 CDN 拉取 html2pdf.js 库;加载完之后就再没有别的请求)。库加载完后把页面切到离线(飞行模式),转换器照样工作。对含客户姓名、财务数据、内部模板,或任何你不愿被复制到陌生人硬盘上的 HTML,都可放心使用。
常见问题
支持哪些 HTML/CSS 特性?
html2pdf 支持标准 HTML 和 CSS,包括布局、字体、颜色、图片和表格。高级功能(动画、JavaScript、媒体查询)受限。为获得最佳效果,请使用内联 CSS 或 <style> 标签,而非外部样式表。
如何在 HTML 中包含图片?
使用 data URI 嵌入图片,或确保外部图片 URL 可访问且支持 CORS。Base64 编码的图片可靠性最高。示例:<img src="data:image/png;base64,…" />
PDF 里的文字为什么不能选?
因为 html2pdf.js 是先把 HTML 渲染为一张 canvas 图像、再把这张图嵌进 PDF。PDF 里的「文字」实际上是文字的栅格图像,不是真正的字形。这是「视觉保真」的代价:PDF 长得跟浏览器预览完全一样,但你不能搜、不能复制、屏幕阅读器读不到。要拿到真正可选的 PDF 文本,替代方案是:用浏览器自带的「另存为 PDF」(文件 → 打印 → 另存为 PDF,产生可选文本且免费);用 Puppeteer 的 page.pdf() 这种服务端工具,它具备 Chromium 完整的 PDF 生成流水线;或者写 JavaScript 直接调用 jsPDF 的 doc.text() 原语(工作量大得多)。
为什么我的预览与 PDF 不同?
预览显示的是您 HTML 在浏览器中的渲染效果。某些 CSS 特性在 PDF 中呈现不同。在生成最终 PDF 前,请先测试复杂布局,必要时调整边距或字号。
能否在 HTML 中添加分页?
可以,使用 CSS 分页属性:为任意元素添加 page-break-before: always; 或 page-break-after: always;。在 CSS3 中,为获得更好的兼容性可使用 break-before: page; 或 break-after: page;。
我的 HTML 会被上传到服务器吗?
不会。你粘的 HTML 和生成的 PDF 都留在你的浏览器里。唯一的网络请求是页面加载时从一个公开 CDN 拉取 html2pdf.js 库本身;加载完成之后就再没有出站请求了。点 Generate 时打开 DevTools 的 Network 选项卡验证一下,或者库加载完后把页面切到离线(飞行模式),转换器照样工作。对含客户数据、财务细节、内部业务模板,或任何你不愿被第三方 PDF 服务看到的内容,都可放心使用。