轻松搞定网页截图,html2canvas入门教程

0 阅读7分钟

点赞 + 关注 + 收藏 = 学会了

html2canvas 简介

html2canvas 是一个纯前端的 JavaScript 库,能直接在浏览器里把 HTML 元素 “拍” 成 Canvas 图片。不用麻烦后端接口,就能实现网页截图、生成分享海报、保存页面快照等需求。

安装方法

html2canvas 支持两种常见的安装方式,根据你的项目环境选就行:

1. npm /yarn 安装(推荐)

如果你的项目用了 Webpack、Vite 等构建工具,直接用包管理器安装:

# npm 安装
npm install html2canvas

# yarn 安装
yarn add html2canvas

本文使用 Vite 创建 Vue3 项目,通过 Vue3 的语法来讲解。在其他框架使用 html2canvas 用法也是差不多的。

2. CDN 引入

如果是简单的 HTML 项目,直接在页面里引入 CDN 链接:

<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>

基础用法

先看一个最简单的例子:点击按钮,把指定的 div 转成 Canvas 并显示在页面上。

<template>
  <div>
    <!-- 要截图的区域 -->
    <div ref="captureRef" style="padding: 20px; background: #f0f0f0;">
      <p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
    </div>

    <!-- 截图按钮 -->
    <button @click="handleCapture">点击截图</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'

// 获取要截图的 DOM 元素
const captureRef = ref(null)

// 截图函数
const handleCapture = async () => {
  // 调用 html2canvas,等待生成 Canvas
  const canvas = await html2canvas(captureRef.value)
  // 把 Canvas 加到页面上看看效果
  document.body.appendChild(canvas)
}
</script>

这段代码看似简单,但第一个坑也出现了。

此时如果在“截图区”加多一个 h2,结果可能会出乎你所料。

<!-- 要截图的区域 -->
<div ref="captureRef" style="padding: 20px; background: #f0f0f0;">
	<h2>雷猴</h2>
	<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div>

<h2> 标题的样式没跟着生成出来啊。。。

解决方法很简单,不使用浏览器默认样式,给所有标签都加上指定样式。

<template>
  <div>
    <!-- 要截图的区域 -->
    <div 
      ref="captureRef" 
      class="capture-area" 
      style="padding: 20px; background: #f0f0f0;"
    >
      <!-- 关键样式建议写在行内,或者确保非 scoped -->
      <h2 class="title">这是要截图的内容</h2>
      <p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
    </div>

    <!-- 截图按钮 -->
    <button @click="handleCapture">点击截图</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'

// 获取要截图的 DOM 元素
const captureRef = ref(null)

// 截图函数
const handleCapture = async () => {
  // 调用 html2canvas,等待生成 Canvas
  const canvas = await html2canvas(captureRef.value)
  // 把 Canvas 加到页面上看看效果
  document.body.appendChild(canvas)
}
</script>

<style scoped>
.capture-area {
  width: 400px;
  box-sizing: border-box;
  border: 1px solid #ccc;
}
.title {
  font-size: 24px;
  font-weight: bold;
  margin: 0 0 10px 0;
}
</style>

常用配置选项

html2canvas 提供了很多配置项,能帮你解决各种场景问题,这里列几个最常用的:

配置项类型默认值说明
scalenumberwindow.devicePixelRatio缩放比例,默认用设备像素比,提高截图清晰度(设为 1 会模糊)。
useCORSbooleanfalse是否允许加载跨域图片,设为 true 才能正确显示跨域图片。
backgroundColorstring#ffffffCanvas 背景色,设为 null 可以得到透明背景。
loggingbooleanfalse是否在控制台打印日志,调试时可以设为 true 看问题。
scrollXnumber0截图时的水平滚动偏移,解决页面滚动导致的内容错位。
scrollYnumber0截图时的垂直滚动偏移,同上。

如果你要截的元素包含图片,而且这张图片和你的网站存在跨域情况,大概率会出现图片出空白的情况。

<template>
  <div>
    <!-- 要截图的区域 -->
    <div 
      ref="captureRef" 
      class="capture-area" 
      style="padding: 20px; background: #f0f0f0;"
    >
      <!-- 关键样式建议写在行内,或者确保非 scoped -->
      <h2 class="title">这是要截图的内容</h2>
      <img src="https://iili.io/fcR7gSe.md.png" alt="" style="width: 140px;">
      <p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
    </div>

    <!-- 截图按钮 -->
    <button @click="handleCapture">点击截图</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'

// 获取要截图的 DOM 元素
const captureRef = ref(null)

// 截图函数
const handleCapture = async () => {
  // 调用 html2canvas,等待生成 Canvas
  const canvas = await html2canvas(captureRef.value)
  // 把 Canvas 加到页面上看看效果
  document.body.appendChild(canvas)
}
</script>

<style scoped>
.capture-area {
  width: 400px;
  box-sizing: border-box;
  border: 1px solid #ccc;
}
.title {
  font-size: 24px;
  font-weight: bold;
  margin: 0 0 10px 0;
}
</style>

要解决这个问题需要2步操作。

  1. 图片服务器配置 Access-Control-Allow-Origin: *(允许跨域)
  2. html2canvas 配置 useCORS: true

如果想更稳妥一点,还可以给图片标签加 crossorigin="anonymous" 属性。

iili.io 这个图床是允许跨域的,所以我们直接在 html2canvas 里配置 useCORS: true 即可。

// 省略部分代码

const canvas = await html2canvas(captureRef.value, {
  useCORS: true
})

高级用法:导出并下载图片

生成 Canvas 后,通常需要把它转成图片文件让用户下载,这里用 toDataURL 实现

<template>
  <div>
    <!-- 要截图的区域 -->
    <div 
      ref="captureRef" 
      class="capture-area" 
      style="padding: 20px; background: #f0f0f0;"
    >
      <!-- 关键样式建议写在行内,或者确保非 scoped -->
      <h2 class="title">这是要截图的内容</h2>
      <img src="https://iili.io/fcR7gSe.md.png" alt="" style="width: 140px;">
      <p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
    </div>

    <!-- 截图按钮 -->
    <button @click="handleCapture">点击截图</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'

// 获取要截图的 DOM 元素
const captureRef = ref(null)

// 截图函数
const handleCapture = async () => {
  // 调用 html2canvas,等待生成 Canvas
  const canvas = await html2canvas(captureRef.value, { useCORS: true });
  
  // 1. 把 Canvas 转成 PNG 格式的 base64 数据
  const imgData = canvas.toDataURL('image/png');
  
  // 2. 创建下载链接
  const link = document.createElement('a');
  link.download = '我的截图.png'; // 下载的文件名
  link.href = imgData;
  
  // 3. 触发点击下载
  link.click();
}
</script>

<style scoped>
.capture-area {
  width: 400px;
  box-sizing: border-box;
  border: 1px solid #ccc;
}
.title {
  font-size: 24px;
  font-weight: bold;
  margin: 0 0 10px 0;
}
</style>

常见坑点及避坑指南

html2canvas 虽然好用,但坑也不少。

跨域图片不显示或报错

前面已经提到了,如果截图里有跨域图片(比如图床的图),默认会显示空白。原因是浏览器的同源策略限制,html2canvas 无法直接读取跨域图片的像素。

解决方法

  • 图片服务器配置 Access-Control-Allow-Origin: *(允许跨域)
  • 给图片标签加 crossorigin="anonymous" 属性
  • html2canvas 配置 useCORS: true
<!-- 图片标签加 crossorigin -->
<img src="https://example.com/image.jpg" crossorigin="anonymous">

CSS 样式显示异常

部分 CSS 属性(如 transformbox-shadow、复杂渐变、伪元素 ::before/::after)可能渲染不对,甚至完全不显示。

html2canvas 是通过解析 DOM 和 CSS 手动绘制 Canvas 的,不是所有 CSS 都支持。

解决方法

  • 尽量用简单的 CSS 布局,避免太复杂的特效
  • 把复杂样式(如渐变、阴影)转成图片代替
  • 查看官方文档的 CSS 支持列表,避开不支持的属性

自定义字体渲染失败

用了自定义字体(如 @font-face),截图里却变成了默认字体。

html2canvas 截图时,字体可能还没加载完,就用了默认字体渲染。

解决方法

  • 等待字体加载完成后再截图,用 document.fonts.ready 即可
document.getElementById('btn').addEventListener('click', async () => {
  // 等待所有字体加载完成
  await document.fonts.ready;
  
  const element = document.getElementById('capture');
  const canvas = await html2canvas(element);
  document.body.appendChild(canvas);
});

滚动条导致截图不全或有滚动条

如果要截图的元素有滚动条,截图会包含滚动条,或者内容被截断。

解决方法

  • 截图前先隐藏滚动条,截图后恢复
const element = document.getElementById('capture');
// 保存原来的 overflow 样式
const originalOverflow = element.style.overflow;
// 隐藏滚动条
element.style.overflow = 'hidden';

const canvas = await html2canvas(element, {
  scrollX: 0,
  scrollY: 0 // 重置滚动偏移
});

// 恢复原来的样式
element.style.overflow = originalOverflow;

iframe 内容无法捕获

如果页面里有 iframe,html2canvas 无法截图 iframe 里的内容。

同源策略限制,无法直接访问 iframe 内部的 DOM。

解决方法

  • 如果 iframe 和主页面同域,可以手动获取 iframe 里的元素再截图
  • 如果跨域,基本无解,建议换其他方案(比如后端截图)

页面元素太多导致性能差

截图区域元素多、图片大时,生成 Canvas 会很慢,甚至浏览器卡顿。

解决方法

  • 适当降低 scale(比如设为 1.5 而不是 2)
  • 截图前隐藏不必要的元素(比如 display: none
  • 只截图需要的部分,不要截整个页面

SVG 元素显示异常

直接截图 SVG 可能会变形、错位,甚至不显示。

解决方法

  • 先把 SVG 转成图片,再插入 DOM 截图。可以用 canvg 库辅助转换,或者手动把 SVG 转成 base64 图片
// 简单的 SVG 转图片示例
const svgElement = document.querySelector('svg');
const svgData = new XMLSerializer().serializeToString(svgElement);
const img = new Image();
img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgData)));

// 等图片加载完后,替换原来的 SVG,再截图
img.onload = async () => {
  svgElement.parentNode.replaceChild(img, svgElement);
  const canvas = await html2canvas(element);
  document.body.appendChild(canvas);
};

z-index 层级错乱

截图里的元素层级和实际页面不一样,该在上面的元素跑到下面了。

html2canvas 对 z-index 的解析有时会出问题,尤其是元素没有显式设置 position 时。

解决方法

  • 给需要层级的元素显式设置 position(如 relativeabsolute
  • 调整 DOM 顺序(后面的元素会覆盖前面的),代替 z-index

点赞 + 关注 + 收藏 = 学会了