HTMLSVG vs Canvas

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>.

HTML
<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.

HTML
<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.

Tip
You are not limited to one or the other. It is common to render a UI with SVG icons while a separate game or chart canvas handles high-frequency animation elsewhere on the same page.
Note
There is also WebGL, a 3D drawing API that also renders into a <canvas> element. It follows the same pixels-not-DOM-nodes tradeoffs as the 2D canvas context, just with hardware-accelerated 3D rendering.