为什么明明用Tailwind写得工工整整的订单页面,一到打印就字体变大、表格错位、背景全无?
为什么每次改打印模板,都要拉着后端同学重新生成PDF,或者让UI设计师再出一套专用样式?
——因为大多数Web打印方案,根本不认你写好的CSS。

两年前,我也被困在这个怪圈里。直到我发现了一个叫 web-print-pdf 的 npm 包,它的理念简单到让人怀疑:“直接用你前端的HTML和CSS,原样打印,原样生成PDF。”

今天这篇文章,不聊晦涩的内核原理,不吹嘘企业级架构,只聊一件事:如何用最舒服的方式,把网页变成高质量的PDF或纸质文档。


01 你需要的不是新模板,而是“尊重CSS”的打印工具

先复盘一下,你现在是怎么处理打印需求的?

方案A:window.print() + @media print

@media print {
  .invoice { 
    width: 100%; 
    background: white; 
    font-size: 12pt; 
  }
}

问题:

· 样式经常“抽风”——明明屏幕上完美,打印出来边距全乱
· 无法生成PDF保存,只能硬打印
· 依然要弹窗,无法静默

方案B:jsPDF + html2canvas

const canvas = await html2canvas(element);
const pdf = new jsPDF();
pdf.addImage(canvas.toDataURL(), 'PNG', 0, 0, 210, 297);

问题:

· 生成的是图片PDF,文字不可选中,放大全是锯齿
· 内存暴涨,长文档容易崩溃
· 完全抛弃了你精心编写的语义化HTML结构

方案C:后端无头浏览器(Puppeteer/Playwright)

const page = await browser.newPage();
await page.setContent(html);
await page.pdf({ path: 'output.pdf' });

问题:

· 需要维护一个后端服务,或者嵌入Node.js环境
· 前端改了样式,还要通知后端同步更新——协作成本陡增

发现共性了吗?
所有方案都逼你为打印单独维护一套逻辑。要么牺牲控制力,要么牺牲开发效率。


02 web-print-pdf:让打印回归“所见即所得”

第一次看到 web-print-pdf 的示例代码,我被它的简单惊到了:

import { printHtml } from 'web-print-pdf';

// 打印当前页面某个区域
await printHtml({
  content: document.getElementById('invoice').innerHTML,
  // 其他参数都是可选的——打印机、纸张、静默…
});

不需要额外定义打印模板,不需要学习新的DSL,不需要后端参与。
你的Vue组件、React组件、原生HTML——直接传进去,打印出来是什么样,就是你在浏览器里看到的样。


🔥 完全CSS控制,不是“尽力还原”

web-print-pdf 基于 Playwright 内核,它对CSS的支持度与最新版Chrome完全一致。

这意味着:

· ✅ Flex/Grid布局 —— 原封不动
· ✅ 自定义字体 —— 不会回退成系统默认
· ✅ 背景色、渐变色 —— 不会莫名消失
· ✅ 圆角、阴影 —— 保留全部细节
· ✅ 媒体查询 —— @media print 依然有效

你甚至可以直接用Tailwind、UnoCSS这类原子化框架,打印样式和屏幕样式共用一套类名。

<div class="p-4 bg-white shadow rounded border border-gray-200">
  <!-- 这套类名,屏幕和打印通用 -->
</div>

无需“打印版”和“屏幕版”两套皮肤,这是前端工程师最舒服的工作流。


03 不止打印:PDF预览与生成,一样CSS优先

很多场景不需要直接打印,而是先生成PDF预览,确认无误后再输出。

web-print-pdf 的 previewHtml 方法,会返回一个真正的PDF文件URL:

import { previewHtml } from 'web-print-pdf';

const pdfUrl = await previewHtml({
  content: document.getElementById('report').innerHTML,
  options: {
    paperSize: 'A4',
    margins: { top: 20, right: 20, bottom: 20, left: 20 }
  }
});

// 嵌入 iframe 预览,或直接下载
window.open(pdfUrl);

这个PDF不是截图,文字是可选的、可搜索的,矢量元素无限清晰。
而这一切,只需要你提供一段HTML——所有样式控制权,依然在你手里。


04 对比一下:为什么它更“简单易用”?

工具/方案 是否需额外学习 是否维护两套样式 文字可选PDF 前端直接调用 指定打印机
window.print() 否 是 ❌ ✅ ❌
Print.js 轻微 是 ❌ ✅ ❌
jsPDF+html2canvas 中等 是 ❌ ✅ ❌
后端Puppeteer 高 是 ✅ ❌ ❌
web-print-pdf 极低 否 ✅ ✅ ✅

核心差异只有一条:
其他工具要你适应它的规则;
web-print-pdf 是它适应你的规则。


05 真实案例:一个Vue订单打印,从30分钟到30秒

之前帮一家电商公司改造后台打印模块。他们的旧流程:

  1. 前端写好订单详情 → 2. 传给后端 → 3. 后端用模板引擎再渲染一遍 → 4. 生成PDF → 5. 返回前端 → 6. 前端调起打印预览

6个环节,只要前端样式微调,后端模板就必须同步修改。

用 web-print-pdf 之后:

<template>
  <div ref="invoiceContainer">
    <!-- 完全复用现有的订单组件样式 -->
    <OrderDetails :order="currentOrder" />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { printHtml } from 'web-print-pdf';
import OrderDetails from './OrderDetails.vue';

const invoiceContainer = ref();

const handlePrint = async () => {
  await printHtml({
    content: invoiceContainer.value.innerHTML,
    silent: true,          // 静默打印,不弹窗
    printer: 'Invoice_Printer'
  });
};
</script>

前端独立,后端0改动。
一个上午,整个打印模块重构完成。


06 适用场景:哪些项目最适合?

· ✅ 电商/ERP后台 —— 订单、发货单、发票打印,样式复杂且频繁变更
· ✅ 医疗/政务系统 —— 检验报告、凭证打印,要求排版绝对精准
· ✅ 财务报表系统 —— 长表格、多分页,需生成高保真PDF存档
· ✅ 任何使用现代前端框架(Vue/React)的项目 —— 组件即模板,零成本复用

一句话总结:
只要你会写HTML和CSS,你就已经会用它。


07 开始使用:从npm install到首次打印,只需3分钟

npm install web-print-pdf

打印一段HTML:

import { printHtml } from 'web-print-pdf';

await printHtml({
  content: '<h1 style="color:red;">测试打印</h1>',
  silent: false  // 设为true可静默
});

生成PDF预览:

import { previewHtml } from 'web-print-pdf';

const url = await previewHtml({
  content: '<div class="invoice">...</div>',
  options: { paperSize: 'A4' }
});

⚠️ 注意:web-print-pdf 需要搭配一个轻量级本地服务使用。
这个服务只需安装一次,所有Web项目共享。
具体安装方式见项目 README,全程图形化,普通运维即可操作。


Web打印不应该成为前端的“畏途”。

你已经在UI和UX上投入了大量心血,为什么到了打印环节,就要被迫妥协、重新发明轮子?

web-print-pdf 不是要教你如何打印,而是把你早已掌握的能力——HTML、CSS、JavaScript——无缝延伸到打印机。

它没有改变前端的工作流,只是移除了“打印需要特殊处理”这个陈旧假设。


npm i web-print-pdf
GitHub / npm 搜索直达

你的CSS,值得被认真对待。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐