Skip to content

canvas 画布基础

HTML5 的 <canvas> 元素提供了一个可通过 JavaScript 绘制图形的画布。它可以用于绘制图表、游戏图形、数据可视化、图像处理等。本节将介绍 canvas 的基本概念、HTML 结构和 fallback 内容。

前置知识

阅读本节前,建议先了解:异步解码

基础概念

<canvas> 是 HTML5 引入的图形绘制元素。与 <img> 直接显示图片不同,<canvas> 本身只是一个空的矩形区域——所有图形内容都需要通过 JavaScript 的 Canvas API 来绘制。

canvas 提供了两种绘图上下文:2D Context(最常用,用于 2D 图形绘制)和 WebGL Context(用于 3D 图形)。本系列教程主要关注 2D Context。

语法

基本语法

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>canvas 基础</title>
</head>
<body>
  <h1>canvas 基本语法</h1>

  <!-- 最简单的 canvas -->
  <canvas id="myCanvas" width="400" height="300">
    您的浏览器不支持 canvas。
  </canvas>

  <hr>

  <!-- 带样式的 canvas -->
  <canvas id="styledCanvas"
          width="600" height="400"
          style="border: 1px solid #ccc; border-radius: 8px;">
    您的浏览器不支持 canvas。
  </canvas>
</body>
</html>

详细说明

canvas 属性

属性说明示例
width画布宽度(像素)width="400"
height画布高度(像素)height="300"

canvas 尺寸的重要性

canvas 的 widthheight 属性定义了绘图缓冲区的大小(即像素分辨率)。CSS 的 width/height 只影响 canvas 的显示尺寸,不改变缓冲区大小。如果 CSS 尺寸与属性尺寸不一致,图形会被缩放,可能导致模糊。

Fallback 内容

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>canvas Fallback</title>
</head>
<body>
  <h1>canvas 回退内容</h1>

  <canvas id="myCanvas" width="400" height="300">
    <!--
      canvas 标签内的内容只在浏览器不支持 canvas 时显示
      支持 canvas 的浏览器会忽略这些内容
    -->

    <!-- 方式 1:纯文本提示 -->
    您的浏览器不支持 canvas,请升级浏览器。

    <!-- 方式 2:提供替代图片 -->
    <!-- <img src="chart.png" alt="图表"> -->

    <!-- 方式 3:提供下载链接 -->
    <!-- <p>请 <a href="chrome.html">下载 Chrome</a></p> -->
  </canvas>

  <script>
    // 检测浏览器是否支持 canvas
    var canvas = document.getElementById('myCanvas');
    if (canvas.getContext) {
      var ctx = canvas.getContext('2d');
      ctx.fillStyle = '#4285f4';
      ctx.fillRect(50, 50, 300, 200);
      ctx.fillStyle = '#fff';
      ctx.font = '24px sans-serif';
      ctx.fillText('Canvas 支持正常', 100, 160);
    }
  </script>
</body>
</html>

canvas 尺寸 vs CSS 尺寸

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>canvas 尺寸</title>
  <style>
    .canvas-large {
      /* CSS 尺寸:显示为 600x450 */
      width: 600px;
      height: 450px;
      border: 2px solid #333;
    }
  </style>
</head>
<body>
  <h1>canvas 尺寸 vs CSS 尺寸</h1>

  <!--
    属性尺寸:300x225 的绘图缓冲区
    CSS 尺寸:600x450 的显示区域
    结果:图形被放大 2 倍,可能模糊
  -->
  <canvas id="scaledCanvas"
          class="canvas-large"
          width="300" height="225">
    不支持 canvas
  </canvas>

  <p>上面的 canvas 属性尺寸为 300x225,但 CSS 放大到了 600x450。</p>

  <script>
    var canvas = document.getElementById('scaledCanvas');
    var ctx = canvas.getContext('2d');

    // 绘制一个红色矩形
    ctx.fillStyle = '#e74c3c';
    ctx.fillRect(0, 0, 150, 112);

    // 绘制一个蓝色矩形
    ctx.fillStyle = '#3498db';
    ctx.fillRect(150, 112, 150, 113);

    // 文字会因放大而模糊
    ctx.fillStyle = '#fff';
    ctx.font = '14px sans-serif';
    ctx.fillText('放大会模糊', 80, 120);
  </script>
</body>
</html>

2D 与 WebGL 上下文

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>canvas 上下文</title>
</head>
<body>
  <h1>2D 与 WebGL 上下文</h1>

  <!-- 2D 上下文画布 -->
  <h2>2D Context</h2>
  <canvas id="canvas2d" width="400" height="200"
          style="border: 1px solid #ccc;"></canvas>

  <br><br>

  <!-- WebGL 上下文画布 -->
  <h2>WebGL Context</h2>
  <canvas id="canvasWebGL" width="400" height="200"
          style="border: 1px solid #ccc;"></canvas>

  <script>
    // 获取 2D 上下文
    var canvas2d = document.getElementById('canvas2d');
    var ctx = canvas2d.getContext('2d');
    ctx.fillStyle = '#2ecc71';
    ctx.fillRect(0, 0, 400, 200);
    ctx.fillStyle = '#fff';
    ctx.font = '20px sans-serif';
    ctx.fillText('2D Canvas', 150, 110);

    // 获取 WebGL 上下文
    var glCanvas = document.getElementById('canvasWebGL');
    var gl = glCanvas.getContext('webgl');
    if (gl) {
      gl.clearColor(0.18, 0.52, 0.95, 1.0);
      gl.clear(gl.COLOR_BUFFER_BIT);
    }
  </script>
</body>
</html>

实战示例

简单的 canvas 图形

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>canvas 示例</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      text-align: center;
    }
    canvas {
      border: 2px solid #ddd;
      border-radius: 8px;
      margin: 20px 0;
    }
  </style>
</head>
<body>
  <h1>Canvas 图形绘制</h1>

  <canvas id="demoCanvas" width="500" height="400">
    您的浏览器不支持 canvas。
  </canvas>

  <script>
    var canvas = document.getElementById('demoCanvas');
    var ctx = canvas.getContext('2d');

    // 背景
    ctx.fillStyle = '#1a1a2e';
    ctx.fillRect(0, 0, 500, 400);

    // 蓝色矩形
    ctx.fillStyle = '#4285f4';
    ctx.fillRect(50, 50, 150, 100);

    // 红色圆形
    ctx.beginPath();
    ctx.arc(350, 100, 50, 0, Math.PI * 2);
    ctx.fillStyle = '#e74c3c';
    ctx.fill();

    // 绿色三角形
    ctx.beginPath();
    ctx.moveTo(250, 250);
    ctx.lineTo(150, 380);
    ctx.lineTo(350, 380);
    ctx.closePath();
    ctx.fillStyle = '#2ecc71';
    ctx.fill();

    // 文字
    ctx.fillStyle = '#fff';
    ctx.font = 'bold 20px sans-serif';
    ctx.fillText('Canvas Demo', 170, 40);
  </script>
</body>
</html>

注意事项

  • canvas 的 width/height 属性定义绘图缓冲区,CSS 尺寸只影响显示
  • canvas 标签内的文本是回退内容,仅在浏览器不支持时显示
  • canvas 默认尺寸为 300x150 像素
  • canvas 内容是像素数据,不会被搜索引擎索引
  • canvas 不支持 DOM 事件绑定到绘制的内容上
  • 高 DPI 屏幕需要手动处理像素比

最佳实践

  • 始终设置 canvas 的 width/height 属性
  • 使用 CSS 控制显示尺寸,保持属性尺寸为实际像素大小
  • 在 canvas 内提供回退内容
  • 使用 JavaScript 检测 getContext 支持情况
  • 处理高 DPI 屏幕(使用 devicePixelRatio
  • 对于简单的图形,考虑使用 SVG 替代

下一节

继续学习:canvas 绑定与上下文

参考链接