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

html2canvas与jsPDF在Safari和Chrome中渲染元素尺寸不一致问题排查

跨浏览器一致渲染PDF(解决Safari中SVG过大问题)

问题背景

使用html2canvas + jsPDF生成PDF时,Chrome与Safari渲染结果存在差异:Safari中的SVG元素显示过大。已手动设置页面、窗口及canvas尺寸,尝试过dpi和scale参数,但dpi无效,scale仅导致图像模糊(小于1时),未解决尺寸不一致问题。

原代码:

export async function downloadPDFScorecard(printContent, fileName) {
  console.info("download scorecard!");
  const imgWidth = 1142; 
  const pageHeight = 800;  
  const pageWidth = 1142;
  const marginY = 80;
  
  const jsPDFOpt = {
    orientation: 'l',
    unit: 'px',
    format: [pageHeight, pageWidth], 
    compress: false,
    floatPrecision: 16
   }

  const html2canvasOpt = {
    dpi: 300,
    scale: 1.2,
    width: 1142,
    height: 1256,
    windowWidth: 1142,
    windowHeight: 1256,
    x: 0,
    y: 0,
    logging: true,
    allowTaint: true,
    useCORS: true,
    removeContainer: true
  }

  await html2canvas(printContent, html2canvasOpt).then( (canvas) => {
      const imgHeight = canvas.height * imgWidth / canvas.width;
      let heightLeft = imgHeight;
      const positionX = 70;
      let positionY = 40;
      var img = canvas.toDataURL("image/jpeg", 1);
      var doc = new jsPDF(jsPDFOpt);
      console.log("pg 1", {positionX, positionY, imgWidth, imgHeight})
      doc.addImage(img, 'JPEG', positionX, positionY, imgWidth, imgHeight, 'NONE', 0);

      heightLeft -= pageHeight;
      positionY = -730;
      console.log("pg 2", {positionX, positionY, imgWidth, imgHeight})
      doc.addPage().addImage(img, 'JPEG', positionX, positionY, imgWidth, imgHeight);

      doc.save(`${fileName}.pdf`);
  });
}

解决方法

1. 强制SVG元素的尺寸规则

给所有需要渲染的SVG元素添加明确的width、height和viewBox属性,避免浏览器自动计算导致的差异:

svg {
  width: 100%; /* 或固定值,根据布局需求调整 */
  height: auto;
  viewbox: 0 0 [原始宽度] [原始高度]; /* 替换为SVG实际的viewBox值 */
}

如果是内联SVG,直接在标签上设置这些属性,确保缩放比例在所有浏览器中一致。

2. 优化html2canvas配置

  • 移除dpi参数(html2canvas的dpi是通过scale模拟的,手动设置会和浏览器设备像素比冲突)
  • 改用基于设备像素比的动态scale,同时固定useCORS和allowTaint,关闭windowWidth/windowHeight(强制使用元素自身尺寸)

修改后的html2canvas配置:

const html2canvasOpt = {
  scale: window.devicePixelRatio * 1.2, // 结合设备像素比保证清晰度
  width: printContent.offsetWidth, // 使用元素实际宽度
  height: printContent.offsetHeight, // 使用元素实际高度
  logging: true,
  allowTaint: true,
  useCORS: true,
  removeContainer: true,
  imageTimeout: 10000 // 增加超时时间,确保SVG加载完成
}

3. 统一jsPDF的单位与尺寸计算

将jsPDF的单位从px改为pt(印刷行业标准单位),避免不同浏览器对px的解析差异:

const A4_WIDTH_PT = 595.28;
const A4_HEIGHT_PT = 841.89;
const jsPDFOpt = {
  orientation: 'l',
  unit: 'pt',
  format: 'a4', // 使用标准A4格式,或自定义横向尺寸[841.89, 595.28]
  compress: false,
  floatPrecision: 16
}

然后在计算图像尺寸时,将canvas像素转换为pt:

const pdfImgWidth = A4_WIDTH_PT - 140; // 减去左右边距(对应原positionX=70)
const pdfImgHeight = (canvas.height * pdfImgWidth) / canvas.width;

4. 修正分页逻辑

避免硬编码positionY = -730,改用动态计算剩余高度:

let heightLeft = pdfImgHeight;
let positionY = 40; // 初始上边距

doc.addImage(img, 'JPEG', 70, positionY, pdfImgWidth, pdfImgHeight);
heightLeft -= (A4_HEIGHT_PT - 80); // 减去上下边距(40*2)

if (heightLeft > 0) {
  doc.addPage();
  positionY = -heightLeft + 40; // 动态计算第二页的Y偏移
  doc.addImage(img, 'JPEG', 70, positionY, pdfImgWidth, pdfImgHeight);
}

修改后的完整代码

export async function downloadPDFScorecard(printContent, fileName) {
  console.info("download scorecard!");
  const A4_WIDTH_PT = 595.28;
  const A4_HEIGHT_PT = 841.89;
  const contentWidth = printContent.offsetWidth;
  const contentHeight = printContent.offsetHeight;
  
  const jsPDFOpt = {
    orientation: 'l',
    unit: 'pt',
    format: 'a4',
    compress: false,
    floatPrecision: 16
  }

  const html2canvasOpt = {
    scale: window.devicePixelRatio * 1.2,
    width: contentWidth,
    height: contentHeight,
    logging: true,
    allowTaint: true,
    useCORS: true,
    removeContainer: true,
    imageTimeout: 10000
  }

  const canvas = await html2canvas(printContent, html2canvasOpt);
  const pdfImgWidth = A4_WIDTH_PT - 140; // 左右边距各70pt
  const pdfImgHeight = (canvas.height * pdfImgWidth) / canvas.width;
  let heightLeft = pdfImgHeight;
  const positionX = 70;
  let positionY = 40;

  const img = canvas.toDataURL("image/jpeg", 1);
  const doc = new jsPDF(jsPDFOpt);

  doc.addImage(img, 'JPEG', positionX, positionY, pdfImgWidth, pdfImgHeight);
  heightLeft -= (A4_HEIGHT_PT - 80); // 上下边距各40pt

  if (heightLeft > 0) {
    doc.addPage();
    positionY = -heightLeft + 40;
    doc.addImage(img, 'JPEG', positionX, positionY, pdfImgWidth, pdfImgHeight);
  }

  doc.save(`${fileName}.pdf`);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 08:34:54