SVG vs Canvas
HTML gives you two very different ways to draw graphics in the browser: <svg> and <canvas>. Both can render shapes, lines, text, and images, but they work on completely different models. Picking the wrong one for a job leads to code that is slow, hard to style, or inaccessible.
SVG: vector graphics as DOM nodes
<svg> (Scalable Vector Graphics) describes an image using shapes — circles, paths, rectangles, text — as XML markup. Every shape becomes a real node in the DOM, just like a <div> or <p>.
<svg viewBox="0 0 100 100" width="100" height="100"> <circle cx="50" cy="50" r="40" fill="#3b82f6" /> <text x="50" y="55" text-anchor="middle" fill="white">Hi</text> </svg>
Each shape is a DOM element you can select, style with CSS, and attach event listeners to.
Vector-based — scales to any size or resolution with zero quality loss (perfect for icons, logos, and print).
Because it is DOM, screen readers can read text and title/desc elements inside it, making SVG naturally more accessible.
Great for a moderate number of static or lightly-animated shapes: icons, charts, diagrams, logos, simple illustrations.
Gets slow when you have thousands of independently animated elements, because the browser must manage that many DOM nodes.
Canvas: a pixel-based drawing surface
<canvas> is a single DOM element — a blank rectangle of pixels. You draw onto it imperatively with JavaScript (usually the 2D context or WebGL), and once something is drawn, the browser has no memory of it as a shape — it is just pixels.
<canvas id="stage" width="200" height="200"></canvas>
<script>
const ctx = document.getElementById('stage').getContext('2d');
ctx.fillStyle = '#3b82f6';
ctx.beginPath();
ctx.arc(100, 100, 40, 0, Math.PI * 2);
ctx.fill();
</script>Only one DOM node no matter how much you draw, so it scales far better to large numbers of moving objects.
Raster-based — resolution is fixed to the canvas pixel dimensions; scaling it up blurs the content.
Nothing inside is individually selectable, styleable with CSS, or announced to assistive technology by default — you must add your own accessible fallback content.
Ideal for games, real-time data visualization with huge point counts, image and video manipulation, and complex particle or physics animation.
Requires you to redraw everything yourself on every frame — there is no automatic shape persistence.
Side-by-side comparison
Aspect | SVG | Canvas |
|---|---|---|
Rendering model | Vector (DOM elements) | Raster (pixels) |
Scaling | Lossless at any size | Blurs when scaled up |
DOM access | Yes — each shape is a node | No — one opaque element |
Styling | CSS and inline attributes | Only via drawing commands |
Events per shape | Native (click, hover, etc.) | Manual hit-testing required |
Accessibility | Better by default (real DOM, text nodes) | Needs manual ARIA / fallback content |
Best for | Icons, logos, charts, diagrams, static art | Games, animations, image processing, huge datasets |
Performance with many objects | Degrades (DOM overhead) | Stays fast (single surface) |
How to choose
Need crisp icons or logos that must look good at every zoom level? Use SVG.
Need a chart with a few dozen or hundred data points that should be clickable or hoverable? Use SVG.
Building a game, a particle system, or animating thousands of elements at 60fps? Use Canvas (or WebGL).
Doing pixel-level image manipulation (filters, cropping, drawing on top of a photo)? Use Canvas.
Unsure and the graphic is mostly static? Default to SVG — it is more accessible and easier to maintain.
<canvas> element. It follows the same pixels-not-DOM-nodes tradeoffs as the 2D canvas context, just with hardware-accelerated 3D rendering.