SnapDOM 与 html2canvas 选型
两者都是纯前端、将 DOM 元素导出为图片的库,适用于分享卡片、海报生成、工单截图、导出报告等场景。
说明:SnapDOM,它通过克隆 DOM + SVG
foreignObject,借助浏览器原生渲染引擎完成截图,是 html2canvas 的现代替代方案。
SnapDOM GitHub 仓库:github.com/zumerlab/snapdom
html2canvas 同样是一个开源项目GitHub 仓库:github.com/niklasvh/html2canvas
目录
- SnapDOM 与 html2canvas 选型
- 一、能实现什么
- SnapDOM([@zumer/snapdom](https://github.com/zumerlab/snapdom))
- html2canvas([html2canvas](https://html2canvas.hertzen.com/))
- 共同局限
- 二、实现原理
- SnapDOM:克隆 DOM + 浏览器渲染
- html2canvas:遍历 DOM + JS 重绘 Canvas
- 三、差异对比
- SnapDOM 浏览器支持
- html2canvas 浏览器支持
- 四、哪种更好?
- 五、其他类似库
- 六、快速用法
- SnapDOM
- html2canvas
- 七、总结
一、能实现什么
SnapDOM(@zumer/snapdom)
- 将任意 DOM 子树导出为PNG、JPG、WebP、SVG、Canvas、Blob
- 支持Shadow DOM、伪元素
::before/::after、CSS 变量、counter()/counters()、line-clamp - 支持同源
iframe截图 - 可嵌入 Web 字体、背景图、外链图片(跨域需代理)
- 插件体系:PDF 导出、水印、自定义后处理等
- 一次克隆、多次导出(
const result = await snapdom(el))
html2canvas(html2canvas)
- 将 DOM 绘制到Canvas,再通过
toDataURL/toBlob得到 PNG/JPG - 支持常见 2D 样式:背景色、边框、文字、部分渐变与阴影
- 配置项丰富:
scale、useCORS、backgroundColor、ignoreElements等 - 生态成熟、示例多,但官方自 2022 年后无稳定版发布,README 仍标注实验性质
共同局限
- 无法截取跨域且未开启 CORS 的图片/字体(会空白或污染 Canvas)
- 无法截取
<video>当前帧、WebGL 画布、部分原生控件 - 不是「整页滚动长截图」专用方案(需自行拼接或换方案)
- 浏览器安全策略限制下,无法截取用户未授权的页面内容
二、实现原理
SnapDOM:克隆 DOM + 浏览器渲染
DOM 元素 → 深克隆(含 Shadow DOM) → 内联计算样式、伪元素、字体、图片 → 包裹进 SVG <foreignObject> → 序列化为 data:image/svg+xml → 转为 PNG / JPG / WebP / Blob核心思路:不自己画像素,而是把「浏览器已经会画的东西」交给浏览器画。
简化原理代码:
// 1. 克隆节点并内联样式constclone=element.cloneNode(true);inlineComputedStyles(clone);inlinePseudoElements(clone);// ::before / ::after → 真实 DOM 节点awaitinlineImagesAndFonts(clone);// 2. 包进 SVG foreignObjectconstsvg=`<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}"> <foreignObject width="100%" height="100%"> <div xmlns="http://www.w3.org/1999/xhtml">${clone.outerHTML}</div> </foreignObject> </svg>`;constsvgUrl='data:image/svg+xml;charset=utf-8,'+encodeURIComponent(svg);// 3. 栅格化为位图constimg=newImage();img.src=svgUrl;awaitimg.decode();constcanvas=document.createElement('canvas');canvas.getContext('2d').drawImage(img,0,0);html2canvas:遍历 DOM + JS 重绘 Canvas
DOM 元素 → 递归遍历每个节点 → 读取 getComputedStyle → 用 Canvas 2D API 模拟 CSS 绘制 → 输出 Canvas核心思路:在 JavaScript 里重新实现一套 CSS 绘制器,不依赖 SVG foreignObject。
简化原理代码:
asyncfunctionhtml2canvas(element,options){constcanvas=document.createElement('canvas');constctx=canvas.getContext('2d');constbounds=element.getBoundingClientRect();canvas.width=bounds.width*options.scale;canvas.height=bounds.height*options.scale;asyncfunctionrenderNode(node){if(node.nodeType===Node.TEXT_NODE){drawText(ctx,node,getComputedStyle(node.parentElement));return;}conststyle=getComputedStyle(node);drawBackground(ctx,node,style);// 颜色、渐变(部分支持)drawBorder(ctx,node,style);drawBoxShadow(ctx,node,style);// 有限支持for(constchildofnode.childNodes){awaitrenderNode(child);}// 伪元素需额外处理,且支持不完整}awaitrenderNode(element);returncanvas;}三、差异对比
| 维度 | SnapDOM | html2canvas |
|---|---|---|
| 渲染方式 | 克隆 + SVG foreignObject,浏览器原生绘制 | JS 遍历 DOM,Canvas 2D 模拟 CSS |
| 性能 | 通常快一个数量级以上(官方基准:简单元素约 30–100×) | 复杂 DOM 明显变慢 |
| 伪元素 | 较完整(内联为真实节点) | 部分支持,易丢失 |
| Shadow DOM | 支持 | 不支持 |
| CSS 变量 | 完整 | 部分 |
counter() | 支持 | 不支持 |
| 输出格式 | SVG、PNG、JPG、WebP、Canvas、Blob | 主要 PNG/JPG(经 Canvas) |
| 插件扩展 | 有 | 无 |
| 维护状态 | 活跃更新(2025–2026) | 2019–2022 后几乎停更 |
| 依赖 | 0 | 少量(css-line-break 等) |
| 上手难度 | 简单,API 更现代 | 简单,文档与案例多 |
| 兼容性 | 现代浏览器 | 更广的老浏览器覆盖 |
SnapDOM 浏览器支持
| 浏览器 | 支持版本 | 说明 |
|---|---|---|
| Chrome / Edge | 90+ | 完全支持,原生性能 |
| Firefox | 88+ | 完全支持,原生性能 |
| Safari / WebKit | 14+ | 完全支持,但需特殊处理(如预热机制) |
| Mobile Safari (iOS) | iOS 14+ | 完全支持,同样需要预热 |
| Chrome Android | 90+ | 完全支持 |
特别说明:SnapDOM 在 Safari 上需要额外的“预热”流程来确保字体和图片加载完成,并会自动将 box-shadow 转换为 filter: drop-shadow 以保证渲染效果。
html2canvas 浏览器支持
现代版本(如 @c2stack/html2canvas 1.4.1):要求浏览器原生支持 ES2020+。
| 浏览器 | 支持版本 |
|---|---|
| Chrome | 80+ |
| Firefox | 75+ |
| Safari | 13.1+ |
| Edge | 80+ |
传统版本(含 Polyfill):通过引入 es6-promise 等 Polyfill,可以支持更古老的浏览器:
- Firefox 3.5+
- Google Chrome
- Opera 12+
- IE9+
- Safari 6+
四、哪种更好?
新项目优先选 SnapDOM,理由:
- 性能更好:大节点、复杂样式下差距明显
- 还原度更高:伪元素、Shadow DOM、CSS 变量等更接近真实页面
- 持续维护:bug 修复与新特性在跟进
- API 更顺手:
toPng/toSvg/download一步到位
仍可考虑 html2canvas 的情况:
- 维护老项目,已有大量 html2canvas 集成代码
- 需要兼容非常老的浏览器环境
- 只需极简 DOM、样式简单、性能要求不高
需要服务端高质量整页截图时,两者都不是最优解,应改用Puppeteer / Playwright等无头浏览器方案。
五、其他类似库
| 库 | 特点 | 备注 |
|---|---|---|
| html-to-image | 基于 dom-to-image 改进,SVG foreignObject 思路 | 轻量,维护中等 |
| dom-to-image | 早期 foreignObject 方案 | 已较少维护 |
| dom-to-image-more | dom-to-image 分支,修复部分 bug | 社区 fork |
| modern-screenshot | 现代 API,性能较好 | SnapDOM 竞品之一 |
| rasterizeHTML.js | HTML/SVG 转 Canvas | 偏底层 |
| html-to-image-pro | 商业增强版 | 付费能力 |
| Puppeteer / Playwright | 服务端真实浏览器截图 | 还原度最高,需后端 |
浏览器原生drawElementImage | 实验性 WICG API | 未来可能替代前端库 |
六、快速用法
SnapDOM
import{snapdom}from'@zumer/snapdom';constel=document.querySelector('#card');constimg=awaitsnapdom.toPng(el);document.body.appendChild(img);CDN(ESM):
<scripttype="module">import{snapdom}from'https://cdn.jsdelivr.net/npm/@zumer/snapdom@2/dist/snapdom.mjs';constimg=awaitsnapdom.toPng(document.querySelector('#card'));</script>html2canvas
constcanvas=awaithtml2canvas(document.querySelector('#card'),{scale:window.devicePixelRatio,useCORS:true,});document.body.appendChild(canvas);CDN:
<scriptsrc="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>七、总结
| 场景 | 推荐 |
|---|---|
| 新项目、复杂样式、追求性能与还原度 | SnapDOM |
| 老项目迁移成本高、样式极简 | html2canvas 可继续用 |
| 服务端 PDF/整页/像素级一致 | Puppeteer / Playwright |
| 轻量 foreignObject 方案 | html-to-image / modern-screenshot |
本地可直接打开snapdom-demo.html与html2canvas-demo.html对比效果;若 CDN 加载失败,请检查网络或使用本地 HTTP 服务访问。