
用浏览器把 HTML 详情页导出成长图 / PDF(附核心思路)
写商品详情、图文教程时,经常会遇到这种情况:
- 内容是 HTML 写的,预览很舒服
- 店铺、小程序、网盘说明却只要 长图 或 PDF
- 截屏拼接费劲,打印另存又容易跑版
其实在浏览器里就能做:把 HTML 渲染出来 → 调好宽度 → 截成一张长图,或再塞进 PDF。下面只讲实现思路和关键代码,方便自己改、自己集成。




1. 整体流程
载入 HTML 片段
↓
放进固定宽度的预览容器(如 750 / 1200)
↓
等图片加载完成
↓
DOM → Canvas(截图)
↓
Canvas → PNG 下载
或 Canvas → jsPDF → PDF 下载
宽度建议先定死再截:
| 场景 | 常用宽度 |
|---|---|
| 手机详情长图 | 750 |
| 部分电商稿 | 790 |
| 电脑宽图 | 1200 |
预览用多少宽,导出就按这个宽截,比「先截再缩放」稳得多。
2. 预览容器(先所见,再所得)
<div id="stage" style="width:750px;background:#fff;margin:0 auto;">
<!-- 这里塞你的 HTML 详情片段 -->
</div>
如果原文根节点写了 max-width:750px,在导出容器里可以强制撑满:
#stage .export-root {
max-width: none !important;
width: 100% !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box;
}
宽度切换只改容器,不要改用户 HTML 里每一处样式:
function setPreviewWidth(px) {
document.getElementById('stage').style.width = px + 'px';
}
3. 导出前先等图片
外链图没加载完就截,容易出现空白块:
async function waitForImages(root) {
const imgs = [...root.querySelectorAll('img')];
await Promise.all(
imgs.map((img) => {
if (img.complete && img.naturalWidth) return;
return new Promise((resolve) => {
img.addEventListener('load', resolve, { once: true });
img.addEventListener('error', resolve, { once: true });
});
})
);
}
外链图若站点不允许跨域,Canvas 会「污染」或缺图。实务上常见处理:
- 图床开启 CORS;或
- 导出前改成本地可访问路径;或
- 用能把资源嵌进结果的截图库(仍依赖对方是否放行)
4. DOM 转长图(两种常见做法)
方案 A:html2canvas(兼容广)
async function exportPng(stage, scale = 2) {
await waitForImages(stage);
const canvas = await html2canvas(stage, {
scale, // 2 = 高清,但个别排版可能和预览略有差异
useCORS: true,
backgroundColor: '#ffffff',
width: stage.offsetWidth,
height: stage.scrollHeight,
});
canvas.toBlob((blob) => {
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'export.png';
a.click();
});
}
注意:scale > 1 时,库会按放大后的逻辑重算文字,行内带背景的代码块最容易和浏览器预览对不齐。不对齐时优先试 scale: 1。
方案 B:基于 SVG foreignObject 的截图(更贴预览)
很多「精确模式」工具会走类似 modern-screenshot / html-to-image 这条路:先克隆 DOM,再画进 Canvas,文字换行通常更接近真实页面。
// 示意:具体 API 以你引入的库为准
const canvas = await modernScreenshot.domToCanvas(stage, {
scale: 2,
backgroundColor: '#ffffff',
});
工程上可以:默认精确模式,失败再回退 html2canvas。
5. 长图再转 PDF
有了 Canvas 之后,用 jsPDF 很直接:
async function exportPdf(canvas, mode = 'long') {
const { jsPDF } = window.jspdf;
const img = canvas.toDataURL('image/jpeg', 0.92);
const pxToMm = 0.264583; // 按 96dpi 近似
if (mode === 'long') {
// 单页长 PDF:页面尺寸跟图走
const w = canvas.width * pxToMm;
const h = canvas.height * pxToMm;
const pdf = new jsPDF({
orientation: w > h ? 'l' : 'p',
unit: 'mm',
format: [w, h],
});
pdf.addImage(img, 'JPEG', 0, 0, w, h);
pdf.save('export.pdf');
return;
}
// A4 分页:一张长图切多页
const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
const pageW = pdf.internal.pageSize.getWidth();
const pageH = pdf.internal.pageSize.getHeight();
const imgW = pageW;
const imgH = (canvas.height * imgW) / canvas.width;
let heightLeft = imgH;
let position = 0;
pdf.addImage(img, 'JPEG', 0, position, imgW, imgH);
heightLeft -= pageH;
while (heightLeft > 0.5) {
position -= pageH;
pdf.addPage();
pdf.addImage(img, 'JPEG', 0, position, imgW, imgH);
heightLeft -= pageH;
}
pdf.save('export.pdf');
}
浏览器对 Canvas 高度有上限(常见大约一万多像素量级)。内容特别长时,需要降清晰度、拆段截取,或换服务端渲染(Puppeteer 一类),这是前端方案的硬边界。
6. 减少「预览正常、导出错位」
实操里最有用的几条:
- 预览宽度 = 导出逻辑宽度(例如直接用 750,而不是 375 再 ×2 指望布局一样)
- 出问题先把清晰度改成 1x
- 行内
code/ 带背景的span可加:
code, kbd, samp {
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
}
短路径文字必要时 display: inline-block; white-space: nowrap;,避免截图引擎把灰底拆成两截。
7. 最小可运行骨架(拼起来)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>HTML → 长图 Demo</title>
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
</head>
<body>
<button id="btn">导出 PNG</button>
<div id="stage" style="width:750px;margin:20px auto;background:#fff;padding:16px;">
<h1>示例标题</h1>
<p>把你的详情 HTML 贴到这里。</p>
</div>
<script>
document.getElementById('btn').onclick = async () => {
const stage = document.getElementById('stage');
const canvas = await html2canvas(stage, {
scale: 2,
useCORS: true,
backgroundColor: '#ffffff',
});
const a = document.createElement('a');
a.download = 'demo.png';
a.href = canvas.toDataURL('image/png');
a.click();
};
</script>
</body>
</html>
本地保存成 .html,用 Chrome / Edge 打开即可试。正式使用再补:宽度预设、PDF、精确截图引擎、跨域与错位处理。
8. 小结
- 核心不是「神奇算法」,而是 固定宽度预览 + DOM 截图 +(可选)写入 PDF
- 难度主要在:图片跨域、超长画布、高清缩放导致的文字错位
- 自己写个 Demo 很快;要做成每天能用的成品,还得把预览、预设、导出选项和避坑打磨一遍
如果你只是想直接用现成的本地小工具(调宽度预览、导出 PNG/PDF),可以在这边看看整理好的版本:
https://zhixuanxingqiu.com
(浏览器打开即用,按需自取;本文只讲原理,方便学习与二次改造。)
&spm=1001.2101.3001.5002&articleId=163638226&d=1&t=3&u=afaa33d9cc79470c8e5acb0796261a03)
459

被折叠的 条评论
为什么被折叠?



