跳至正文
Tooling — Canvas 2D API 能力地图:绘制、变换、合成与导出

Canvas 2D API 能力地图:绘制、变换、合成与导出

MDN:Canvas API

AI 参与说明(Agent:Grok Bot、Cursor):Grok Bot(Blog)编排选题与交付,Cursor Cloud 撰写。能力范围以 2026-11-03 读取的 MDN Canvas API、CanvasRenderingContext2D、HTMLCanvasElement、getContext()、OffscreenCanvas、Path2D、ImageData、globalCompositeOperation、save() 以及「在 canvas 中使用跨源图像」为准。Context7 免费额度返回 Monthly quota exceeded 后,改用 Context7 Pro(库 ID /websites/developer_mozilla_en-us)核对 Path2D、fill() / isPointInPath() 的填充规则。模型 grok-4.7-high-fast,提供方 xAI,执行入口 Cursor Cloud。reasoning effort 未作为独立字段取得运行记录。个别接口的浏览器支持仍以 MDN 兼容性表为准;广泛可用标记若带星号,表示部分成员支持不一致。

Canvas 2D 在 <canvas> 的位图上即时绘制。调用 fillRect() 或 fill() 之后,留下的是像素;上下文不保留一个可稍后移动的矩形对象。要改画面,就再画一次,或改 ImageData 再写回。

同一元素通过 getContext() 进入一种上下文。二维绘制用 "2d",得到 CanvasRenderingContext2D。硬件加速的二维和三维绘制走 WebGL,见 WebGL API 能力地图。

英文术语中文名称简要解释
HTMLCanvasElement画布元素页面上的 <canvas>,持有一块位图
CanvasRenderingContext2D二维绘图上下文往这块位图上画形状、文字和图像的接口
Path2D路径对象可以保存、复制并反复绘制的路径
ImageData像素数据一块矩形像素,按 RGBA 排成一维数组
OffscreenCanvas离屏画布不必挂在文档上、可以转到 Worker 的画布
ImageBitmap图像位图已解码、可绘制或可转移所有权的位图
globalCompositeOperation全局合成操作新像素如何与位图上已有像素合并
current transformation matrix当前变换矩阵后续绘制会先经过的平移、缩放和旋转

中文名称只作导读。后文固定使用英文名称。

这些对象怎么接在一起

一块可见的 <canvas> 是 HTMLCanvasElement。getContext("2d") 返回 CanvasRenderingContext2D,真正的绘制调用都在它上面。Path2D 单独保存几何,再交给 fill()、stroke() 或 clip()。getImageData() 把位图读成 ImageData,putImageData() 写回。导出、采集和把控制权交给 OffscreenCanvas,则是元素上的方法。

flowchart TB
  Element["HTMLCanvasElement"] --> GetContext["getContext"]
  GetContext --> Context2D["CanvasRenderingContext2D"]
  GetContext --> BitmapCtx["ImageBitmapRenderingContext"]
  Path["Path2D"] --> Context2D
  Context2D --> Pixels["ImageData"]
  Element --> Export["toDataURL / toBlob / captureStream"]
  Element --> Transfer["transferControlToOffscreen"]
  Transfer --> Offscreen["OffscreenCanvas"]
  Offscreen --> Context2D

OffscreenCanvas 也可以自己 new 出来,不经过页面上的元素。它的二维上下文接口是 OffscreenCanvasRenderingContext2D,继承二维上下文的绝大部分成员。

上下文从哪里来

HTMLCanvasElement.getContext() 的 contextType 决定这块画布进入哪一种模式。同一元素上,相同的 contextType 始终返回第一次拿到的那个上下文对象。标识不受支持,或这块画布已经进入另一种模式时,返回 null。

contextType返回用途
"2d"CanvasRenderingContext2D本页的二维绘制
"webgl",以及 "experimental-webgl"WebGLRenderingContextWebGL 1
"webgl2"WebGL2RenderingContextWebGL 2
"webgpu"GPUCanvasContextWebGPU,配置方式不在本页
"bitmaprenderer"ImageBitmapRenderingContext用一张 ImageBitmap 替换画布内容

"experimental-webgl" 在 MDN 的说明里用于尚未通过一致性测试,或驱动尚不稳定的 WebGL 实现。WebGPU 的属性不在 getContext() 的第二个参数里,而在 GPUCanvasContext.configure()。

调用 transferControlToOffscreen() 之后,再对原来的 HTMLCanvasElement 调用 getContext() 会抛出 InvalidStateError。

width 与 height 是位图的像素尺寸。缺省或非法(例如负数)时,宽默认 300,高默认 150。没有单独的 CSS 宽高时,这两个值也是元素的 CSS 像素尺寸。CSS 把元素显示得比位图更大时,浏览器会拉大这块位图。MDN 的无障碍说明指出:画布里的像素不是矢量,放大后会变糊。工程上常把位图像素设得比 CSS 显示尺寸更大,用来减轻这种拉大。

创建 "2d" 上下文时可以带这些属性:

属性MDN 上的含义
alpha为 false 时,浏览器知道背景始终不透明,绘制透明内容可以更快
colorSpace"srgb"(默认)或 "display-p3"
colorType"unorm8"(默认,8 位无符号)或 "float16"
desynchronized提示用户代理把画布绘制与事件循环解耦,以降低延迟
willReadFrequently计划频繁读回像素时设为 true,改用软件二维画布,频繁 getImageData() 时更省内存

上表来自 MDN 的 getContext()。Canvas API 的广泛可用标记带星号,表示部分成员的浏览器支持并不一致,落地时对照该页的兼容性表。

最小绘制和 MDN 首页示例相同。页面上要有一块 <canvas>。下面这段跑在浏览器里,预期是一块绿色矩形:左上角在 (10, 10),宽 150、高 100。getContext("2d") 得到 null 时,后续调用不会发生。

javascript
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

ctx.fillStyle = "green";
ctx.fillRect(10, 10, 150, 100);

主要接口

MDN 的 Canvas API 参考列出这些接口。与 WebGLRenderingContext 相关的接口记在 WebGL 文档里。

接口在整条链路里的位置
HTMLCanvasElement元素、尺寸、取上下文、导出、采集、转到离屏
CanvasRenderingContext2D二维绘制、样式、变换、合成、像素读写
OffscreenCanvasRenderingContext2D离屏画布上的二维上下文
CanvasGradientcreateLinearGradient()、createRadialGradient()、createConicGradient() 的返回值
CanvasPatterncreatePattern() 的返回值
Path2D可保留的路径;Worker 中可用
ImageData像素块;Worker 中可用
ImageBitmap已解码位图,可转移
ImageBitmapRenderingContext只负责把一张 ImageBitmap 铺进可见画布
TextMetricsmeasureText() 的测量结果
OffscreenCanvas离屏绘制;Worker 中可用。Baseline 自 2023-03 起广泛可用,部分成员支持不一致
CanvasCaptureMediaStreamTrackcaptureStream() 给出的实时画面轨道

CanvasRenderingContext2D 的 Baseline 自 2015-07 起广泛可用,部分成员支持不一致。Path2D 自 2016-08 起广泛可用。

绘制

矩形三个方法直接落笔,不经过当前路径。

方法结果
clearRect()把矩形内像素设为透明黑,清掉原有内容
fillRect()用当前 fillStyle 填充矩形
strokeRect()用当前 strokeStyle 描矩形边

路径先记在当前路径或一个 Path2D 里,再统一填充或描边。

方法加进路径的内容
beginPath()清空子路径,开始一条新路径
moveTo()把下一段的起点移到 (x, y)
lineTo()直线连到 (x, y)
bezierCurveTo()三次贝塞尔曲线
quadraticCurveTo()二次贝塞尔曲线
arc() / arcTo()圆弧
ellipse()椭圆弧
rect() / roundRect()矩形或圆角矩形
closePath()从当前点直线回到当前子路径起点;已经闭合或只有一个点时不做任何事

Path2D() 可以空构造、从另一个 Path2D 复制,或从一段 SVG 路径数据构造,例如 "M10 10 h 80 v 80 h -80 Z"。addPath() 把另一条路径并进来。上下文上的路径方法,Path2D 上也有一套,因此几何可以留着反复画。复制之后再改副本,不会改到原来的对象。

方法对当前路径或传入的 Path2D 做什么
fill()按 fillStyle 填充。填充规则为 "nonzero"(默认)或 "evenodd"
stroke()按 strokeStyle 描边
clip()用当前子路径作裁剪,之后的绘制只出现在裁剪区域内
drawFocusIfNeeded()若给定元素处于焦点,沿当前路径画焦点环
isPointInPath()点是否在路径内部
isPointInStroke()点是否落在描边区域内

"nonzero" 是非零环绕规则,"evenodd" 是奇偶规则。路径自交或嵌套时,"evenodd" 可以让中间留下孔;默认的 "nonzero" 会把这个孔也填上。MDN 对 isPointInPath() 的参数说明是:检查用的 x、y 不受上下文当前变换影响。

文字有填充、描边和测量。测量结果是 TextMetrics。

成员作用
fillText() / strokeText()在 (x, y) 填充或描边文字
measureText()返回 TextMetrics
font字体,默认 "10px sans-serif"
textAlignstart(默认)、end、left、right、center
textBaselinetop、hanging、middle、alphabetic(默认)、ideographic、bottom
directionltr、rtl、inherit(默认)
letterSpacing / wordSpacing字距、词距,默认 0px
fontKerningauto(默认)、normal、none
fontStretch从 ultra-condensed 到 ultra-expanded,默认 normal
fontVariantCapsnormal、小型大写字母等
textRenderingauto(默认)、optimizeSpeed、optimizeLegibility、geometricPrecision
lang这段绘制文字的语言

drawImage() 把图像画进画布,有多种参数形式,用来控制源矩形和目标矩形。跨源图像的限制见下文「读回与导出」。

像素级访问走 ImageData。data 是一行接一行、从左上到右下的 RGBA。width、height、colorSpace、pixelFormat 只读。data 可以是 Uint8ClampedArray 或 Float16Array。

成员作用
createImageData()新建一块透明黑的 ImageData
getImageData()读出矩形区域的像素
putImageData()把 ImageData 画回位图;可以只画 dirty 矩形
ImageData()用现成数组和尺寸构造;Worker 里常用这个构造函数,因为那里没有 createImageData()

imageSmoothingEnabled 关闭后,缩放图像不再做平滑。imageSmoothingQuality 设置平滑质量。

样式、变换、合成与状态

填充和描边的颜色或样式:

成员作用默认
fillStyle形状内部黑
strokeStyle形状轮廓黑
createLinearGradient()沿一条线段的渐变返回 CanvasGradient
createRadialGradient()由两个圆定义的径向渐变同上
createConicGradient()绕一点的锥形渐变同上
createPattern()用图像按重复方式铺贴返回 CanvasPattern
filter套用 CSS 或 SVG 滤镜,例如亮度和模糊见 MDN

线型只影响描边。

成员作用默认或取值
lineWidth线宽1.0
lineCap端点butt(默认)、round、square
lineJoin拐角miter(默认)、round、bevel
miterLimit斜接限制比10
setLineDash() / getLineDash()虚线图案,数组长度为偶数,数值非负空图案即实线
lineDashOffset虚线从哪里开始见 MDN

阴影四项:shadowBlur(默认 0)、shadowColor(默认全透明黑)、shadowOffsetX 与 shadowOffsetY(默认 0)。

变换作用在当前变换矩阵上。后续默认路径、文字、形状和 Path2D 绘制都会经过它。MDN 说明这些方法因历史兼容而保留,接口的其他部分更多使用 DOMMatrix。

方法对矩阵做什么
translate() / rotate() / scale()追加平移、顺时针旋转(弧度)、缩放
transform()用参数描述的矩阵乘到当前矩阵上
setTransform()先重置为单位矩阵,再做一次 transform()
getTransform()读出当前矩阵
resetTransform()重置为单位矩阵

合成由两处控制。globalAlpha 是绘制前乘上的透明度,默认 1.0。globalCompositeOperation 决定新图形如何画到位图上,默认 "source-over",也就是画在已有内容之上。取值来自 MDN 的属性页:

操作结果
source-over新图形盖在已有内容上
source-in只保留新图形与已有内容重叠的部分,其余变透明
source-out新图形只出现在不与已有内容重叠的地方
source-atop新图形只出现在与已有内容重叠的地方
destination-over新图形画到已有内容后面
destination-in只保留两者重叠处的已有内容
destination-out已有内容去掉与新图形重叠的部分
destination-atop已有内容只留在与新图形重叠处,新图形在后面
lighter重叠处颜色相加
copy只显示新图形
xor重叠处变透明,其余照常

混合模式仍是同一个属性的取值:

操作结果
multiply上下层相乘,结果更暗
screen反相后相乘再反相,结果更亮
overlaymultiply 与 screen 的组合
darken / lighten保留两边更暗或更亮的像素
color-dodge / color-burn按 MDN 的除法方式提亮或压暗
hard-light类似 overlay,上下层角色对调
soft-light更柔和的 hard-light
difference / exclusion作差;后者对比更低
hue / saturation / color / luminosity在明度、色相、色度之间取上层或下层

save() 把整个绘制状态压栈,restore() 弹回最近一次。入栈的内容包括当前变换矩阵、当前裁剪区域、当前虚线列表,以及 fillStyle、strokeStyle、globalAlpha、globalCompositeOperation、filter、阴影、线型、字体、imageSmoothingEnabled、imageSmoothingQuality 等属性。MDN 这一页的属性名单里没有当前路径,也没有 lang。当前路径用 beginPath() 处理。

成员作用
save() / restore()压栈、弹栈
reset()重置渲染上下文,包括后备缓冲、状态栈、路径和样式
isContextLost()上下文是否已丢失
getContextAttributes()浏览器实际采用的上下文属性
canvas指回 HTMLCanvasElement;没有关联元素时可能是 null

元素上的 contextlost 在浏览器发现二维上下文丢失时触发,contextrestored 在恢复成功时触发。

动画没有单独的「补间对象」。画面要变,就在下一帧改样式或矩阵,再调用绘制方法。调度通常用 requestAnimationFrame()。MDN 的 OffscreenCanvas 示例说明,Worker 里也可以这样调度。

命中、焦点与无障碍

画布上的命中要自己拿路径去问,浏览器并不知道你画过哪些对象。

能力接口问的是什么
点是否在填充区域内isPointInPath()当前路径,或传入的 Path2D
点是否在描边上isPointInStroke()按当前描边展开的区域
焦点环drawFocusIfNeeded()元素有焦点时,沿当前路径画环

MDN 的无障碍说明:<canvas> 只是一块位图,不提供所绘对象的信息。画在上面的文字在屏幕放大时可读性差,因为那是像素组成的字形,放大后像素变大。无障碍工具也读不到画布内容里的语义。需要表达实质内容时,应另有可访问的 HTML,并把画布当作图像来用。

导出、采集、离屏与 Worker

成员所在接口得到什么
toDataURL()HTMLCanvasElement默认 PNG 的 data URL,分辨率 96dpi
toBlob()HTMLCanvasElement表示这张图像的 Blob
captureStream()HTMLCanvasElementCanvasCaptureMediaStreamTrack,画布表面的实时视频
transferControlToOffscreen()HTMLCanvasElement把控制权交给 OffscreenCanvas
convertToBlob()OffscreenCanvas离屏画布上的 Blob
transferToImageBitmap()OffscreenCanvas最近一帧的 ImageBitmap
transferFromImageBitmap()ImageBitmapRenderingContext用这张位图替换可见画布,并接管所有权

离屏有两条路,都写在 MDN 的 OffscreenCanvas 页上。

一条是自己 new OffscreenCanvas(width, height),在它的上下文里画完,transferToImageBitmap() 取出 ImageBitmap。可见画布用 getContext("bitmaprenderer"),再 transferFromImageBitmap()。一张 OffscreenCanvas 可以把帧交到多个 ImageBitmapRenderingContext。

另一条是 transferControlToOffscreen(),把返回的 OffscreenCanvas 用 postMessage 转到 Worker(转移对象列表里带上它),Worker 里再 getContext()。OffscreenCanvas 是可转移对象。

一旦把其他源、且未经 CORS 许可的数据画进画布,画布就被污染(tainted)。此后读回像素会失败,并抛出 SecurityError。MDN 点名的调用是:

  • 上下文上的 getImageData()
  • 元素上的 toBlob()、toDataURL()、captureStream()

这是为了避免用图像把其他网站上的数据读出来。图像来自 <img> 或 SVG <image> 时,同样不能把画布内容读回去。要合法使用跨源图像,服务器发送允许的 Access-Control-Allow-Origin,页面上的图像设置 crossOrigin(例如 "anonymous")。说明见 在 canvas 中使用跨源图像。

使用时先看的失败

现象MDN 上的原因
getContext() 返回 null标识不支持,或这块画布已经是另一种上下文
getContext() 抛出 InvalidStateError已经 transferControlToOffscreen()
画面被拉糊位图像素少于 CSS 显示尺寸;像素放大后变大
getImageData() 或 toDataURL() 抛出 SecurityError画布已污染
isPointInPath() 和肉眼位置对不上传入的坐标不受当前变换矩阵影响
save() 之后路径还在当前路径不在 MDN 列出的状态栈里
上下文丢失监听元素的 contextlost,并用 isContextLost() 确认

和上层库、WebGL 的分界

Canvas 2D 适合直接画形状、文字、图像和像素。对象很多、需要场景图或精灵批处理时,库会自己维护对象,再调用这些接口或改走 WebGL。站内相关页:可视化工具、PixiJS。

WebGL 仍从同一块 <canvas> 的 getContext("webgl") 或 getContext("webgl2") 进入,但绘制模型换成着色器、缓冲和纹理。二维上下文和 WebGL 上下文不能装在同一元素上。

关联阅读

参考资料

核对日期 2026-11-03。

博客助手

正在打开博客助手…