You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JS生成带页眉页脚的HTML转PDF?解决空白与离线问题

客户端离线HTML转PDF需求及问题解决

核心需求

  • 使用JavaScript在客户端离线完成HTML转PDF
  • 内容分页时,每页自动添加页眉和页脚
  • 支持大数据量及客户端自定义展示属性

遇到的问题

  • 使用html2pdf库生成PDF时,内容开头出现大量空白
  • 尝试jsPDF库,输出效果不符合预期

问题截图:
问题截图

测试用html2pdf代码

<!DOCTYPE html>
<html>
  <head>
    <title>HTML to PDF Example</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
  </head>
  <body>
    <div id="content">
      <h1>Welcome to html2pdf Tutorial</h1>
      <p>
        This is an example of converting HTML content to a PDF file using the
        html2pdf JavaScript library.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p><p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
        lacinia odio vitae vestibulum vestibulum.
      </p>
    </div>

    <button onclick="generatePDF()">Generate PDF</button>

    <script>
      function generatePDF() {
        const element = document.getElementById("content");
        const options = {
          margin: 1,
          filename: "example.pdf",
          image: { type: "jpeg", quality: 0.98 },
          html2canvas: { scale: 2 },
          jsPDF: { unit: "in", format: "letter", orientation: "portrait" },
        };

        html2pdf().set(options).from(element).save();
      }
    </script>
  </body>
</html>

解决方案

1. 修复html2pdf开头空白问题

空白通常由边距过大、渲染偏移导致,调整配置即可:

function generatePDF() {
  const element = document.getElementById("content");
  const options = {
    margin: [0.5, 0.5, 0.5, 0.5], // 缩小边距
    filename: "example.pdf",
    image: { type: "jpeg", quality: 0.98 },
    html2canvas: { 
      scale: 2,
      scrollY: 0, // 强制从顶部渲染,避免滚动偏移
      logging: false
    },
    jsPDF: { unit: "in", format: "letter", orientation: "portrait" },
  };

  html2pdf().set(options).from(element).save();
}

额外检查#content元素的CSS,确保无多余padding/margin。

2. 为html2pdf添加分页页眉页脚

利用html2pdf的onPdfSave回调,遍历所有页面插入页眉页脚:

function generatePDF() {
  const element = document.getElementById("content");
  const opt = {
    margin: [1, 0.5, 1, 0.5], // 预留页眉页脚空间
    filename: "example.pdf",
    image: { type: "jpeg", quality: 0.98 },
    html2canvas: { scale: 2 },
    jsPDF: { unit: "in", format: "letter", orientation: "portrait" },
    onPdfSave: function(pdf) {
      const totalPages = pdf.internal.getNumberOfPages();
      for (let i = 1; i <= totalPages; i++) {
        pdf.setPage(i);
        // 页眉:居中标题
        pdf.text("自定义文档标题", pdf.internal.pageSize.getWidth() / 2, 0.5, { align: "center" });
        // 页脚:页码
        pdf.text(`第 ${i} 页 / 共 ${totalPages} 页`, pdf.internal.pageSize.getWidth() / 2, 10.5, { align: "center" });
      }
    }
  };

  html2pdf().set(opt).from(element).save();
}

3. 替代方案:jsPDF + html2canvas手动控制

若html2pdf效果仍不理想,直接组合两个库,完全手动控制分页逻辑:

async function generatePDF() {
  const content = document.getElementById("content");
  const canvas = await html2canvas(content, { scale: 2 });
  const imgData = canvas.toDataURL("image/jpeg", 0.98);
  const pdf = new jsPDF("portrait", "in", "letter");
  
  const pageWidth = pdf.internal.pageSize.getWidth();
  const pageHeight = pdf.internal.pageSize.getHeight();
  const imgWidth = pageWidth;
  const imgHeight = (canvas.height * imgWidth) / canvas.width;
  let heightLeft = imgHeight;
  let position = 0;

  // 第一页
  pdf.addImage(imgData, "JPEG", 0, position, imgWidth, imgHeight);
  heightLeft -= pageHeight;
  pdf.text("自定义文档标题", pageWidth / 2, 0.5, { align: "center" });
  pdf.text("第 1 页", pageWidth / 2, pageHeight - 0.5, { align: "center" });

  // 分页处理
  while (heightLeft > 0) {
    position = heightLeft - imgHeight;
    pdf.addPage();
    pdf.addImage(imgData, "JPEG", 0, position, imgWidth, imgHeight);
    heightLeft -= pageHeight;
    const currentPage = pdf.internal.getNumberOfPages();
    pdf.text("自定义文档标题", pageWidth / 2, 0.5, { align: "center" });
    pdf.text(`第 ${currentPage} 页`, pageWidth / 2, pageHeight - 0.5, { align: "center" });
  }

  pdf.save("example.pdf");
}

内容的提问来源于stack exchange,提问作者shreyansh goel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 00:29:50