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
相关产品推荐
相关产品推荐

