The <canvas> tag is one of those things in web development that everyone’s heardof - but not everyone truly understands.It’s there, quietly sitting in your HTML toolbox, capable of incredible things - from drawing shapes and animations to building full-blown games and data visualizations.Yet for many developers, it remains a bit of a mystery. <canvas> heard In this article, I’ll try to clear the fog around <canvas> - what makes it special, what you can (and can’t) do with it, and how to actually draw your first shape on it. <canvas> What Makes <canvas> So Different? <canvas> At first glance, <canvas> looks like any other HTML element: <canvas> <canvas id="myCanvas" width="400" height="300"></canvas> <canvas id="myCanvas" width="400" height="300"></canvas> But here’s the thing: unlike a <div>, a <canvas>can’t have child elements inside it.It’s not a container - it’s adrawing surface. <div> <canvas> drawing surface You can’t put buttons, text, or other HTML inside it. Once you start drawing, it’s just you, the pixels, and the2D or WebGL context. 2D WebGL <!-- ❌ This won’t work --> <canvas> <p>This text will never be seen.</p> </canvas> <!-- ❌ This won’t work --> <canvas> <p>This text will never be seen.</p> </canvas> Why? Because <canvas> is rendered as a bitmap, not part of the DOM tree. Everything you draw becomes raw pixels. <canvas> bitmap Everything on Canvas Lives in Pixels Unlike other layout elements that can scale with CSS, a <canvas> only knows one unit of measurement - pixels. <canvas> pixels When you define a canvas like this: <canvas width="400" height="300"></canvas> <canvas width="400" height="300"></canvas> That’s exactly 400×300 pixelsof drawing space. 400×300 pixels You can stretch it with CSS, but that just scales the pixels - it doesn’t change the drawing resolution. This can make your drawings look blurry on high-DPI screens or when the page is resized. So, How Do You Make Canvas Responsive? To make your canvas adjust automatically to its parent size, you’ll need to set its dimensions dynamically in JavaScript and listen for resize events. Here’s a simple pattern: <canvas id="myCanvas"></canvas> <script> const canvas = document.getElementById('myCanvas'); const ctx = canvas.getContext('2d'); function resizeCanvas() { const parent = canvas.parentElement; canvas.width = parent.clientWidth; canvas.height = parent.clientHeight; draw(); // re-draw after resizing } window.addEventListener('resize', resizeCanvas); resizeCanvas(); // initialize once function draw() { ctx.fillStyle = '#ff6600'; ctx.fillRect(20, 20, 100, 100); } </script> <canvas id="myCanvas"></canvas> <script> const canvas = document.getElementById('myCanvas'); const ctx = canvas.getContext('2d'); function resizeCanvas() { const parent = canvas.parentElement; canvas.width = parent.clientWidth; canvas.height = parent.clientHeight; draw(); // re-draw after resizing } window.addEventListener('resize', resizeCanvas); resizeCanvas(); // initialize once function draw() { ctx.fillStyle = '#ff6600'; ctx.fillRect(20, 20, 100, 100); } </script> This way, your canvas automatically fills its parent container, and the draw() function ensures it stays visually consistent whenever the window resizes. draw() And Now…. Let’s Draw Something for Real Once your canvas is ready and sized correctly, drawing on it is surprisingly simple. You just get the context and start issuing drawing commands — kind of like talking to a mini-Photoshop API. <canvas id="paint"></canvas> <script> const canvas = document.getElementById('paint'); const ctx = canvas.getContext('2d'); canvas.width = 400; canvas.height = 300; // Draw a line ctx.strokeStyle = '#4a90e2'; ctx.lineWidth = 5; ctx.beginPath(); ctx.moveTo(50, 50); ctx.lineTo(350, 250); ctx.stroke(); // Draw a circle ctx.fillStyle = '#ff0066'; ctx.beginPath(); ctx.arc(200, 150, 40, 0, Math.PI * 2); ctx.fill(); // Draw text ctx.font = '20px Montserrat'; ctx.fillStyle = '#222'; ctx.fillText('Hello Canvas!', 120, 160); </script> <canvas id="paint"></canvas> <script> const canvas = document.getElementById('paint'); const ctx = canvas.getContext('2d'); canvas.width = 400; canvas.height = 300; // Draw a line ctx.strokeStyle = '#4a90e2'; ctx.lineWidth = 5; ctx.beginPath(); ctx.moveTo(50, 50); ctx.lineTo(350, 250); ctx.stroke(); // Draw a circle ctx.fillStyle = '#ff0066'; ctx.beginPath(); ctx.arc(200, 150, 40, 0, Math.PI * 2); ctx.fill(); // Draw text ctx.font = '20px Montserrat'; ctx.fillStyle = '#222'; ctx.fillText('Hello Canvas!', 120, 160); </script> You’re not working with DOM nodes anymore - you’re literally painting pixelsdirectly onto a surface.Every frame, every animation, every brush stroke has to be drawn again manually (or by your code). literally painting pixels Turning Canvas Into a Mini Paint App Now that we know how to draw on a canvas, let’s make it interactive—so users can draw on it with their mouse (or finger, if they’re on mobile). interactive The logic is simple: Detect when the user presses the mouse (mousedown) Draw lines while the mouse moves (mousemove) Stop drawing when the mouse is released (mouseup) Detect when the user presses the mouse (mousedown) mousedown Draw lines while the mouse moves (mousemove) mousemove Stop drawing when the mouse is released (mouseup) mouseup Let’s put it all together. <canvas id="drawArea"></canvas> <script> const canvas = document.getElementById('drawArea'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Brush settings ctx.strokeStyle = '#0b84ff'; ctx.lineWidth = 4; ctx.lineCap = 'round'; let isDrawing = false; let lastX = 0; let lastY = 0; canvas.addEventListener('mousedown', (event) => { isDrawing = true; [lastX, lastY] = [event.offsetX, event.offsetY]; }); canvas.addEventListener('mousemove', (event) => { if (!isDrawing) return; ctx.beginPath(); ctx.moveTo(lastX, lastY); ctx.lineTo(event.offsetX, event.offsetY); ctx.stroke(); [lastX, lastY] = [event.offsetX, event.offsetY]; }); canvas.addEventListener('mouseup', () => isDrawing = false); canvas.addEventListener('mouseleave', () => isDrawing = false); </script> <canvas id="drawArea"></canvas> <script> const canvas = document.getElementById('drawArea'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Brush settings ctx.strokeStyle = '#0b84ff'; ctx.lineWidth = 4; ctx.lineCap = 'round'; let isDrawing = false; let lastX = 0; let lastY = 0; canvas.addEventListener('mousedown', (event) => { isDrawing = true; [lastX, lastY] = [event.offsetX, event.offsetY]; }); canvas.addEventListener('mousemove', (event) => { if (!isDrawing) return; ctx.beginPath(); ctx.moveTo(lastX, lastY); ctx.lineTo(event.offsetX, event.offsetY); ctx.stroke(); [lastX, lastY] = [event.offsetX, event.offsetY]; }); canvas.addEventListener('mouseup', () => isDrawing = false); canvas.addEventListener('mouseleave', () => isDrawing = false); </script> That’s it - you’ve just created a basic paint tool in less than 40 lines of code! basic paint tool If you open this HTML file in your browser, you can already draw freehand lines like in MS Paint (check out thisfiddle) fiddle A Few Cool Improvements You Can Add Now that it works, you can easily extend it with some fun extras: Color Picker: let users choose a brush color (<input type="color">) Brush Size Slider: control ctx.lineWidth Clear Button: use ctx.clearRect(0, 0, canvas.width, canvas.height) to reset the canvas Touch Support: add listeners for touchstart, touchmove, and touchend Fading Trails: re-draw lines with transparency for ghost-like effects (👻 maybe link to your GhostLine project!) Color Picker: let users choose a brush color (<input type="color">) Color Picker: <input type="color"> Brush Size Slider: control ctx.lineWidth Brush Size Slider: ctx.lineWidth Clear Button: use ctx.clearRect(0, 0, canvas.width, canvas.height) to reset the canvas Clear Button: ctx.clearRect(0, 0, canvas.width, canvas.height) Touch Support: add listeners for touchstart, touchmove, and touchend Touch Support: touchstart touchmove touchend Fading Trails: re-draw lines with transparency for ghost-like effects (👻 maybe link to your GhostLine project!) Fading Trails: One Important Note on Performance When drawing continuously (especially on large canvases), redrawing on every mousemovecan get heavy.To optimize: mousemove Use requestAnimationFrame for smoother rendering Batch draw operations instead of doing them per pixel Consider reducing the resolution on very large canvases Use requestAnimationFrame for smoother rendering requestAnimationFrame Batch draw operations instead of doing them per pixel Consider reducing the resolution on very large canvases Final Thoughts The <canvas>tag might look humble — just an empty box — but it’s a full-fledged graphics engine in disguise.It gives youcontrol over pixels, enabling you to build everything from data visualizations to fluid simulations and drawing apps. <canvas> control over pixels And the best part?It’s all natively supported in every modern browser, no frameworks required. The <canvas> tag doesn’t just render graphics it lets you create worlds, one pixel at a time. The <canvas> tag doesn’t just render graphics it lets you create worlds, one pixel at a time. <canvas> create worlds