使用 Tailwind CSS + 原生 CSS Print 实现完美的网页打印与 PDF 导出

在前端开发中,经常会遇到需要将网页(特别是简历、报告、发票等)导出为 PDF 的需求。比起引入庞大的第三方截图或 PDF 生成库,利用浏览器原生的 `window.print()` 结合 CSS Print 媒体查询,是性能最好、代码最优雅的方案。 但在实际操作中,原生打印常常会遇到**背景色丢失**、**内容被拦腰截断**、**浏览器自带页眉页脚干扰**以及**响应式排版变形**等四大痛点。 本篇笔记总结了如何利用 **Tailwind CSS + 原生 CSS `@media print`** 优雅地解决这些问题,实现 1:1 像素级完美的打印排版。

#type / howto #status / evergreen #tech / dev / frontend #resource / css

[!info] related notes

使用 Tailwind CSS + 原生 CSS Print 实现完美的网页打印与 PDF 导出

在前端开发中,经常会遇到需要将网页(特别是简历、报告、发票等)导出为 PDF 的需求。比起引入庞大的第三方截图或 PDF 生成库,利用浏览器原生的 window.print() 结合 CSS Print 媒体查询,是性能最好、代码最优雅的方案。

但在实际操作中,原生打印常常会遇到背景色丢失内容被拦腰截断浏览器自带页眉页脚干扰以及响应式排版变形等四大痛点。

本篇笔记总结了如何利用 Tailwind CSS + 原生 CSS @media print 优雅地解决这些问题,实现 1:1 像素级完美的打印排版。


💡 核心优化流程与原理

1. 掌控物理纸张:@page 规则

千万不要试图用外层容器的 margin 或绝对定位来模拟打印边距,这极易导致内容错位和滚动条失灵。正确的做法是将边距管理权还给打印机本身:

@media print {
  @page {
    /* 定义纸张尺寸和方向 */
    size: A4 portrait;
    /* 定义黄金打印留白:上下 8mm,左右 15mm */
    margin: 8mm 15mm; 
  }
}

2. 色彩保卫战:强制渲染背景色

为了省墨,浏览器默认会清除网页的所有背景色。即使使用 Tailwind 的 print:bg-gray-100 也可能会失效。必须在全局样式中强制开启色彩调整:

@media print {
  html, body {
    /* 强制浏览器打印背景颜色和图形 */
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
    /* 建议同时重置 body 的底色为纯白 */
    background: white !important;
    color: black !important;
  }
}

💡 提示:对于极为顽固的背景条(例如简历中的小标题背景),建议在 CSS 中显式写入 background-color: #xxx !important; 暴力注入。

3. 丝滑的分页控制:防截断魔法

打印多页内容时,最尴尬的就是一个完整的段落或列表被硬生生切成两半,一半在上一页,一半在下一页。

我们可以使用 break-inside: avoid 来保护最小颗粒度的元素:

@media print {
  /* 保证段落、列表项或自定义的容器不被从中间截断 */
  p, li, .keep-together {
    page-break-inside: avoid;
    break-inside: avoid;
  }
  
  /* 保证标题不会变成页面底部的孤儿(即标题在上一页,正文在下一页) */
  h2, h3 {
    page-break-after: avoid;
    break-after: avoid;
  }
}

4. 元素断舍离:隐藏无关 UI

网页上的导航栏、返回按钮、甚至是“打印”按钮本身,都不应该出现在最终的 PDF 中。

@media print {
  /* 隐藏所有非打印区域 */
  header, footer, nav, aside, .print-hidden {
    display: none !important;
  }
  
  /* 去除超链接的下划线和默认蓝色,保持纸质质感 */
  a {
    text-decoration: none !important;
    color: black !important;
  }
}

5. 排版降维打击:放弃响应式,拥抱绝对单位

在屏幕上,我们习惯用 text-smp-4sm:flex-row。但在打印尺寸(A4)固定的情况下,响应式类名极易引发排版灾难。

最佳实践:

  • 字号锁定:针对高密度信息的简历,放弃 text-sm,直接使用具体像素值如 text-[12.5px]
  • 行高锁定:使用 leading-[1.6] 或类似比例,确保多行文本紧凑。
  • 间距锁定:使用微小的固定间距(如 gap-1.5, mb-2)替代大间距,提升空间利用率。

🚀 终极万能模板 (Global CSS)

将以下代码放入全局样式(如 Astro 的 <style is:global> 或 Next.js 的 globals.css)中,即可为页面赋予完美的打印能力:

CSS

@media print {
  /* 1. 物理尺寸与边距 */
  @page {
    size: A4 portrait;
    margin: 8mm 15mm; 
  }

  /* 2. 基础重置与色彩保留 */
  html, body {
    background: white !important;
    color: black !important;
    margin: 0 !important;
    padding: 0 !important;
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  /* 3. 隐藏不需要打印的网页元素 */
  .no-print, header, footer, nav {
    display: none !important;
  }

  /* 4. 解除页面主容器的宽度限制,让其充满纸张 */
  #resume-wrapper {
    width: 100% !important;
    max-width: none !important;
    margin: 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
  }

  /* 5. 智能分页防截断 */
  p, li, .keep-together {
    page-break-inside: avoid;
    break-inside: avoid;
  }
  h1, h2, h3, h4, h5, h6 {
    page-break-after: avoid;
    break-after: avoid;
  }

  /* 6. 链接静默化 */
  a {
    text-decoration: none !important;
    color: inherit !important;
  }
}

⚠️ 最终用户操作指南(至关重要)

即使代码写得再完美,如果用户在浏览器的打印弹窗中设置错误,依然会翻车。请确保在调用 window.print() 时,提示用户完成以下设置(以 Chrome/Edge 为例):

  1. 展开 更多设置 (More settings)
  2. 🚫 取消勾选 “页眉和页脚” (Headers and footers) —— 这是去掉顶部丑陋网址和底部页码的唯一方法!
  3. 勾选 “背景图形” (Background graphics) —— 确保色块和进度条等元素正常显示。
创建于 2026/3/7 更新于 2026/5/27