Canvas Basics
<canvas> is a blank rectangular drawing surface. By itself, an empty <canvas> renders as nothing more than an invisible box—every pixel on it has to be drawn with JavaScript. That's the fundamental trade-off to understand before anything else: canvas is a pixel-based drawing API, not a markup language for graphics.Declaring a Canvas
canvas-element.html
<canvas id="scene" width="400" height="300"> Your browser doesn't support the canvas element. </canvas>
width/height as HTML attributes (not CSS) to define the canvas's actual pixel grid—sizing it only with CSS stretches or squashes the drawing instead of giving you more pixels to draw on. The text inside the tag is fallback content for browsers that don't support canvas at all.Getting a 2D Rendering Context
<canvas> element does nothing until you grab a rendering context—an object with the drawing methods you'll actually call. The most common is the 2D context.canvas-2d.html
<canvas id="scene" width="400" height="300"></canvas>
<script>
const canvas = document.getElementById('scene');
const ctx = canvas.getContext('2d');
// Draw a filled rectangle
ctx.fillStyle = '#3b82f6';
ctx.fillRect(20, 20, 120, 80);
// Draw a circle (canvas has no built-in "circle" — you draw an arc)
ctx.beginPath();
ctx.arc(250, 60, 40, 0, Math.PI * 2);
ctx.fillStyle = '#ef4444';
ctx.fill();
// Draw text
ctx.font = '16px sans-serif';
ctx.fillStyle = '#111827';
ctx.fillText('Hello, canvas!', 20, 150);
</script>Every shape is drawn imperatively, one method call at a time. Canvas has no memory of "the rectangle I drew a moment ago"—once pixels are painted, they're just pixels. To change or animate a shape, you redraw the whole scene (or the affected region) from scratch.
Canvas vs SVG
SVG (covered in the next lesson) also draws graphics in the browser, but the two work in opposite ways: SVG keeps every shape as an element in the DOM, while canvas only remembers pixels.
Consideration | Canvas | SVG |
|---|---|---|
Representation | Flat pixel bitmap, no memory of individual shapes | Live DOM elements—each shape is inspectable and stylable |
Scaling | Blurs when scaled up (raster) | Stays crisp at any size (vector) |
Best for | Games, complex animations, image/video processing, thousands of moving objects | Icons, diagrams, charts, illustrations, anything needing individual element interactivity |
Accessibility | Content is invisible to screen readers unless you duplicate it as fallback/ARIA | Elements can carry titles/descriptions and are more inspectable by assistive tech |
Editing after drawing | Requires redrawing (no per-shape references) | Just update the element/attribute (e.g. via CSS or the DOM) |
<img> or inline <svg>, a <canvas> with no script attached is just an empty box. If JavaScript fails to load or is disabled, users see only the fallback content (or nothing).A Minimal Animation Loop
canvas-animation.html
<canvas id="scene" width="400" height="150"></canvas>
<script>
const ctx = document.getElementById('scene').getContext('2d');
let x = 0;
function frame() {
ctx.clearRect(0, 0, 400, 150); // erase the previous frame
ctx.fillStyle = '#22c55e';
ctx.fillRect(x, 60, 30, 30);
x = (x + 2) % 400;
requestAnimationFrame(frame);
}
frame();
</script>requestAnimationFrame)—there's no concept of moving "the rectangle" independently, because canvas never kept a reference to it in the first place.Sizing Pitfalls: Attributes vs CSS
width/height attributes say (300×150 by default if omitted), while CSS just stretches that grid to a different display size—causing blurry, distorted drawings.sizing-pitfall.html
<!-- Wrong: canvas still draws at 300x150 internally, then gets stretched --> <canvas id="bad" style="width: 800px; height: 400px;"></canvas> <!-- Right: internal pixel grid matches the intended display size --> <canvas id="good" width="800" height="400"></canvas>
A Simple Interactive Example
Canvas content can respond to user input too—mouse coordinates are read relative to the canvas element, then used in drawing calls.
canvas-drawing.html
<canvas id="pad" width="400" height="200" style="border: 1px solid #ccc;"></canvas>
<script>
const canvas = document.getElementById('pad');
const ctx = canvas.getContext('2d');
let drawing = false;
canvas.addEventListener('mousedown', () => { drawing = true; });
canvas.addEventListener('mouseup', () => { drawing = false; });
canvas.addEventListener('mousemove', (event) => {
if (!drawing) return;
const rect = canvas.getBoundingClientRect();
ctx.fillRect(event.clientX - rect.left, event.clientY - rect.top, 3, 3);
});
</script>Common Use Cases
Use case | Why canvas fits |
|---|---|
2D games | Frequent full-scene redraws at 60fps; no DOM overhead per object |
Data visualization with huge datasets | Thousands of points render faster as pixels than as DOM nodes |
Image editing / filters | Direct pixel manipulation via getImageData/putImageData |
Drawing/whiteboard apps | Freeform strokes map naturally to pixel painting |
Generated thumbnails/QR codes | Programmatic pixel output, often exported via toDataURL() |
<canvas> is a blank drawing surface—set width/height as attributes, not CSS.
Get a rendering context (2D, or WebGL for 3D) before you can draw anything.
Canvas remembers only pixels, not shapes—redrawing is how you update or animate content.
Choose canvas for many changing pixels (games, particle effects); choose SVG for distinct, inspectable, interactive shapes.
Canvas draws nothing without JavaScript—always provide meaningful fallback content.