DEV Community

Million Ways To Code
Million Ways To Code

Posted on

The Canvas Revolution: When Pixels Took Over the Web

Canvas vs. SVG: The Trade-Offs That Matter

I still remember the first time I messed around with <canvas>. It was 2019, and I was building some dumb interactive animation—probably one of those particles-follow-the-mouse things everyone makes when they're learning. Back then, if you wanted custom graphics on the web, your options were basically: wrestle with SVG until it does what you want, or use Flash and immediately lose all credibility. Canvas felt like cheating. A blank rectangle where I could just... paint stuff with JavaScript. No weird XML syntax. No fighting with the DOM. Just pixels and math.

Turns out that little HTML tag would go on to power half the apps I use daily. Google Maps? Canvas. Figma? Canvas. Those fancy data dashboards that plot millions of points without melting your laptop? Also canvas.

But before we go all-in on canvas, we gotta talk about the stuff it sits on top of. You know, the boring but important foundation: semantic HTML.


Why Semantic HTML Still Matters (Yes, Even for Graphics)

Look, I get it. Semantic HTML isn't exciting. Nobody gets hyped about <article> tags. But here's the thing—writing code that actually means something matters more than you think.

When you use <button> instead of <div class="button">, you're not just being pedantic. You're telling the browser, screen readers, and random developers who will maintain your code in three years that this thing is clickable and does something. A <nav> says "this is navigation," not "this is a container with links inside."

<header>
  <h1>My Blog</h1>
  <nav><!-- actual links here --></nav>
</header>
<main>
  <article>
    <h2>Post Title</h2>
    <p>Content goes here...</p>
  </article>
</main>
Enter fullscreen mode Exit fullscreen mode

This stuff builds the DOM—that tree structure browsers use to make sense of your page. Every element becomes a node you can poke at with JavaScript, style with CSS, or query with dev tools when something breaks at 2 AM.

Why should you care about this when we're supposed to be talking about graphics? Because SVG and canvas live in this same world, but they treat it completely differently. SVG elements become part of that DOM tree—every circle, every path, every rectangle shows up as a node you can inspect and manipulate. Canvas? It's just one lonely <canvas> tag hiding a whole universe of pixels that the DOM knows nothing about.


SVG vs. Canvas: Pick Your Poison

Here's a scenario: You're building a dashboard. Simple line chart, tooltips on hover, the usual. Easy, right? Now imagine your boss comes back and says "cool, now make it handle 100,000 data points and let users zoom around in real time." Suddenly the easy solution isn't so easy.

SVG: When You Want Your Graphics in the DOM

SVG is basically XML for drawing. It feels familiar because you're writing tags like HTML:

<svg width="500" height="300">
  <circle cx="100" cy="100" r="40" fill="steelblue" />
  <rect x="200" y="60" width="80" height="80" fill="coral" />
</svg>
Enter fullscreen mode Exit fullscreen mode

Every circle, every rectangle becomes a real DOM element. You can attach click handlers directly, update attributes with JavaScript, style them with CSS. The browser remembers everything you drew—this is called retained mode.

The catch? Memory. Each shape costs something. Render 5,000 circles and suddenly your DOM tree is a bloated mess. Interaction gets sluggish, scrolling feels like wading through molasses, and users start complaining about your "laggy dashboard" on Twitter.

Canvas: When You Just Want to Draw Pixels

Canvas is the opposite. You get a rectangle, a drawing context, and that's it. Nothing persists—you just tell it what to draw, and it draws it:

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

ctx.fillStyle = 'steelblue';
ctx.beginPath();
ctx.arc(100, 100, 40, 0, Math.PI * 2);
ctx.fill();

ctx.fillStyle = 'coral';
ctx.fillRect(200, 60, 80, 80);
Enter fullscreen mode Exit fullscreen mode

This is immediate mode. The browser draws your circle, then immediately forgets it ever happened. Want to move that circle? Gotta clear the whole canvas and redraw everything. It's more work on your end, but there's zero DOM overhead. You can draw hundreds of thousands of shapes because the GPU does the heavy lifting.


The Two Things People Actually Mean When They Say "Scalable"

I've noticed that when developers talk about "scalable graphics," they're usually talking about two completely different things. Mixing them up leads to bad decisions and regret.

1. Resolution Scalability (How It Looks When You Zoom)

Does your graphic look like garbage on a 4K monitor?

SVG wins this one hands down. Vector math means infinite scaling—no pixels, no blur. Canvas is pixel-based by default. Draw something at 100×100 and scale it with CSS? Congrats, you now have a blurry mess. You can fix this by setting the canvas dimensions to match the device pixel ratio, but it's not automatic.

2. Application Scalability (How Much Stuff You Can Throw At It)

How many elements before your browser starts sweating?

Canvas destroys SVG here. No scene graph, no DOM nodes, just raw drawing commands pushed through the GPU. Games, real-time simulations, massive data visualizations—all canvas territory.


Where Canvas Actually Changed the Game

Let's look at some real examples where canvas didn't just make things slightly better—it made things possible that weren't before.

🗺️ Google Maps: How Do You Make Millions of Things Clickable?

Old web maps used static image tiles. Then came interactive maps with SVG markers, which worked fine until you tried to show more than a few hundred points. Google Maps took a different approach: render everything in canvas (actually WebGL, which is canvas on steroids).

But here's the problem—if everything is just pixels, how do you know which restaurant someone clicked on? Google uses this sneaky technique called "color picking":

  • Draw an invisible off-screen buffer where every data point gets a unique RGB color (basically its ID).
  • When the user clicks, check what color is at that pixel in the invisible buffer.
  • Look up which data point has that color.

This happens in milliseconds and works for millions of objects. Google even lets developers use this via their WebglOverlayView API now.

🎨 Figma: What If the Whole UI Was One Canvas?

Figma took a crazy bet: render the entire design interface in WebGL. No DOM elements for shapes, text layers, or frames—just one giant canvas and a ton of math.

This is why real-time collaboration works. When you move a layer, Figma sends a tiny message and everyone's canvas redraws that layer. No DOM diffing, no reflows, no framework fighting itself. Just pixels updating.

📊 Data Visualization: When D3 Grew Up

D3 used to be the king of SVG visualizations. Still is, for small-to-medium datasets. But for huge data, D3 can now use canvas renderers. Observable Plot even lets you decide based on data size:

Plot.plot({
  marks: [
    Plot.dot(data, {
      x: "revenue",
      y: "profit",
      renderer: data.length > 10000 ? "canvas" : "svg"
    })
  ]
})
Enter fullscreen mode Exit fullscreen mode

The library makes the call for you. That's the kind of pragmatism I respect.


How I Decide (After Making All the Wrong Choices First)

I've built enough things that crashed browsers to have some rules of thumb now.

Use SVG when:

  • You need perfect sharpness at any size (logos, icons, diagrams)
  • You want to attach click handlers without writing hit detection logic
  • Accessibility matters (screen readers can actually describe SVG)
  • You have less than like 500 elements

Use canvas when:

  • You're rendering thousands of things
  • Performance is actually important (animations, games, real-time)
  • You need pixel-level control (image filters, video effects)
  • You don't mind managing redraws yourself

And if you're somewhere in between? Layer them. Static background in SVG, dynamic stuff in canvas. Or heavy lifting in canvas, tooltips and overlays in SVG. Nobody says you have to pick just one.


Random Thoughts on AI and All That

I've been thinking a lot about AI tools lately, mostly because I use them constantly. It's wild what you can generate with a prompt now—whole particle systems, chart components, even simple games. But here's the thing: AI doesn't know your actual problem.

It doesn't know that your boss wants tooltips on every single data point. It doesn't know that half your users are on five-year-old phones with integrated graphics. It doesn't know that accessibility isn't optional for your project.

Writing the code was never the hard part. The hard part is figuring out which trade-offs to make. SVG or canvas? Retained mode or immediate mode? DOM convenience or GPU performance? Those decisions don't come from prompts—they come from understanding the problem and the people who have it.

That's honestly why I started Million Ways to Code. Not to show off clever implementations, but to think out loud about the why behind choices. Ten developers, same problem, ten solutions. That's not a bug—that's the whole point.


What's Next?

The web keeps changing. WebGPU is coming. New frameworks every week. But the core questions stay the same: what are we building, who's it for, and what breaks if we do it wrong?

Next time I'm gonna build something simple—maybe a scatter plot with a few thousand points. Nothing fancy, just enough to feel the difference between SVG and canvas in my fingers. I'll probably break stuff and complain about it.

If you've hit performance walls in your own projects, I'd genuinely love to hear about them. What did you try? What worked? What made you want to throw your laptop across the room?

Drop a comment or whatever. No pressure either way.

Thanks for reading. This stuff is messy and human and I'm glad you're here.

Top comments (0)