W3docs

Canvas Intro

Learn the HTML <canvas> element: its coordinate system, the 2D rendering context, high-DPI scaling, accessibility, and runnable drawing examples.

The HTML <canvas> element is a rectangular drawing surface that you control entirely from script. The element itself is just an empty container — it draws nothing on its own. You use JavaScript to issue drawing commands that paint pixels onto it.

This page introduces the <canvas> element, its coordinate system, the 2D rendering context, and the most common drawing operations: shapes, text, gradients, lines, and images.

What is the <canvas> element?

<canvas> gives you a bitmap — a grid of pixels you draw into immediately. Once a shape is painted, the canvas does not remember it as an object; it is just colored pixels. This is the key difference from SVG, where every shape stays a DOM node you can re-style or animate individually.

That trade-off guides when to reach for canvas:

  • Choose <canvas> for pixel-level control, many thousands of objects, fast frame-by-frame animation, games, image processing, charts with lots of data, or particle effects. Because it is "immediate-mode," redrawing is cheap.
  • Choose SVG when you need resolution-independent vectors, scalable icons, a manageable number of shapes you want to inspect, click, or animate via CSS/DOM.
  • Choose CSS for layout, transitions, and effects on regular HTML elements — not for free-form drawing.
Tip

You can place more than one <canvas> element on the same HTML page, each with its own context.

The coordinate system

A canvas uses a 2D coordinate grid. The origin (0, 0) is the top-left corner. The x-axis increases to the right and the y-axis increases downward — note that y grows downward, the opposite of a math graph. A point (100, 60) is therefore 100 pixels from the left edge and 60 pixels from the top.

The drawing area is defined by the width and height attributes (in CSS pixels):

<canvas id="canvas" width="250" height="150"></canvas>
Danger

Set the canvas size with the width and height attributes, not with CSS. CSS width/height only stretch the existing bitmap, which blurs your drawing. Add a border with the style attribute or a class.

The 2D rendering context

You never draw on the <canvas> element directly — you draw through a rendering context, an object that exposes the drawing API. You obtain it with getContext():

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

getContext('2d') returns a CanvasRenderingContext2D, which carries every method and property used below (fillRect, arc, fillText, strokeStyle, and so on). It is the right starting point for almost all 2D drawing.

Other context types exist for different needs:

  • 'webgl' / 'webgl2' — GPU-accelerated 3D (and high-performance 2D) via the OpenGL ES API.
  • 'bitmaprenderer' — displays an ImageBitmap with no drawing API of its own.

This chapter uses only the '2d' context.

Accessibility: fallback content

Anything you place between the opening and closing <canvas> tags is fallback content. Browsers that support canvas ignore it; browsers (or assistive tech) that cannot render the canvas show it instead. Because the drawn pixels are invisible to screen readers, use this space to describe the graphic, or add an aria-label / role so the canvas is announced meaningfully.

<canvas id="canvas" width="250" height="150" role="img" aria-label="A blue circle on a white background">
  A blue circle on a white background.
</canvas>

For interactive canvases (games, drawing apps), provide real focusable HTML controls inside the element as a fallback, since the pixels themselves cannot be tabbed to.

Example of the HTML <canvas> tag:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="canvas" width="250" height="150" style="border:1px solid #1c87c9;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
  </body>
</html>

Example of the HTML <canvas> tag to draw a circle:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="200" height="200" style="border:1px solid #dddddd;">
      HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      ctx.beginPath();
      ctx.arc(100, 100, 60, 0, 2 * Math.PI);
      ctx.strokeStyle = '#009299';
      ctx.stroke();
    </script>
  </body>
</html>

The arc() method takes five arguments: arc(x, y, radius, startAngle, endAngle). Here (100, 100) is the circle's center, 60 is the radius in pixels, and the arc sweeps from angle 0 to 2 * Math.PI. Angles are measured in radians, and a full circle is radians, so 0 to 2 * Math.PI draws the complete circle. beginPath() starts a fresh path, and stroke() outlines it using the current strokeStyle. To fill it instead, set fillStyle and call fill(). Learn more in Canvas drawing and Canvas coordinates.

Example of the HTML <canvas> tag to draw a text:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="350" height="110" style="border:1px solid #dddddd;">
      HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      ctx.font = "40px Arial";
      ctx.fillStyle = '#262ac7';
      ctx.fillText("Canvas Text", 55, 65);
    </script>
  </body>
</html>

fillText(text, x, y) paints filled text at the given coordinates. The font property uses standard CSS font shorthand. See Canvas text for alignment, stroking text, and measuring width.

Example of the HTML <canvas> tag to draw a linear gradient:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="300" height="140" style="border:1px solid #dddddd;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      const grd = ctx.createLinearGradient(0, 0, 300, 0);
      grd.addColorStop(0, "#359900");
      grd.addColorStop(1, "#ffffff");
      ctx.fillStyle = grd;
      ctx.fillRect(20, 20, 250, 100);
    </script>
  </body>
</html>

createLinearGradient(x0, y0, x1, y1) defines the gradient's direction by two points. Here (0, 0) to (300, 0) is a horizontal left-to-right gradient. addColorStop(offset, color) places a color at a position from 0 (start) to 1 (end), so green fades to white. Assigning the gradient to fillStyle makes fillRect(x, y, width, height) paint with it. More in Canvas gradients.

Example of the HTML <canvas> tag to draw a line:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="150" height="150" style="border:1px solid #cccccc;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      ctx.moveTo(0, 0);
      ctx.lineTo(150, 150);
      ctx.strokeStyle = '#86417d';
      ctx.stroke();
    </script>
  </body>
</html>

moveTo(x, y) lifts the "pen" to a starting point without drawing, and lineTo(x, y) adds a straight segment to that point. Nothing appears until you call stroke(). See Canvas drawing for multi-segment paths, line width, and joins.

Example of the HTML <canvas> tag to draw an image:

To stay self-contained (and avoid cross-origin issues — see the note below), this example uses a small inline SVG image as a data URI rather than a remote photo:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <h2>Draw an image with canvas</h2>
    <canvas id="exampleCanvas" width="220" height="120" style="border:1px solid #dddddd;"></canvas>
    <script>
      const canvas = document.getElementById('exampleCanvas');
      const ctx = canvas.getContext('2d');
      const image = new Image();
      image.addEventListener('load', () => {
        // drawImage(image, dx, dy) draws at the given top-left position
        ctx.drawImage(image, 10, 10);
        // Scaled copy: drawImage(image, dx, dy, dWidth, dHeight)
        ctx.drawImage(image, 120, 10, 50, 50);
      });
      image.src =
        "data:image/svg+xml," +
        encodeURIComponent(
          '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
          '<circle cx="50" cy="50" r="45" fill="#1c87c9" /></svg>'
        );
    </script>
  </body>
</html>

drawImage() accepts three forms: drawImage(image, dx, dy), drawImage(image, dx, dy, dWidth, dHeight) to scale, and drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) to crop a source rectangle (s*) and place it into a destination rectangle (d*). Always draw inside the image's load event so the pixels are ready. See Canvas images for more.

Danger

CORS gotcha. Drawing an image from another origin without proper CORS headers "taints" the canvas. After that, getImageData() and toDataURL() throw a security error. If you need to read pixels back from a remote image, the image must be served with permissive CORS headers and loaded with image.crossOrigin = "anonymous" before setting src.

Example of the HTML <canvas> tag to draw a circular gradient:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="260" height="160" style="border:1px solid #cdcdcd;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      const grd = ctx.createRadialGradient(150, 75, 10, 115, 90, 150);
      grd.addColorStop(0, "purple");
      grd.addColorStop(1, "white");
      ctx.fillStyle = grd;
      ctx.fillRect(20, 20, 220, 120);
    </script>
  </body>
</html>

createRadialGradient(x0, y0, r0, x1, y1, r1) blends between two circles: a start circle (center (150, 75), radius 10) and an end circle (center (115, 90), radius 150). The color stops fade from purple at the inner circle to white at the outer one, producing the round glow. Compare with createLinearGradient above and read more in Canvas gradients.

High-DPI (Retina) displays

On high-density screens, one CSS pixel maps to several device pixels. A canvas sized only in CSS pixels therefore looks blurry on those displays. The fix is to scale the bitmap by window.devicePixelRatio and then scale the context so your drawing coordinates stay the same:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const ratio = window.devicePixelRatio || 1;

// CSS size (layout) stays the same:
const cssWidth = 250;
const cssHeight = 150;
canvas.style.width = cssWidth + 'px';
canvas.style.height = cssHeight + 'px';

// Backing bitmap gets more device pixels:
canvas.width = cssWidth * ratio;
canvas.height = cssHeight * ratio;

// Scale once so you keep drawing in CSS-pixel coordinates:
ctx.scale(ratio, ratio);

After this, drawing arc(100, 100, 60, …) produces a crisp circle on both standard and Retina screens.

Practice

Practice
What are the characteristics and usage of the HTML Canvas?
What are the characteristics and usage of the HTML Canvas?
Was this page helpful?