Chapter 39: Canvas Rectangles
Canvas Rectangles in the clearest, most patient, step-by-step way possible.
Imagine I’m sitting right next to you with my screen open. We’re going to build every single example together — slowly, with tiny complete code snippets you can copy-paste and run immediately. No skipping steps, no magic, just plain English explanations, visual thinking, common mistakes highlighted, and repeated patterns until you feel 100% comfortable drawing and controlling rectangles in Canvas.
Canvas Rectangles – Complete Beginner-to-Confident Guide
1. The single most important sentence about rectangles in Canvas
A rectangle in Canvas is not a permanent object you can later move or resize like in SVG. It is four lines (or a filled area) you paint right now using the current brush settings (color, thickness, etc.).
After you call fillRect() or strokeRect() (or rect() + fill()/stroke()), the pixels are just pixels — there is no “rectangle object” anymore.
If you want to move it, change its size, or color → you have to erase the old one (usually by clearing the canvas) and draw a new rectangle at the new position/size/color.
2. The four main ways to draw a rectangle in Canvas
There are four common methods — each has a slightly different use case.
| Method | Code example | When to use it | Filled? | Outlined? | Built-in path? |
|---|---|---|---|---|---|
| fillRect() | ctx.fillRect(x, y, w, h) | Quick filled rectangles (no border needed) | Yes | No | Yes (auto) |
| strokeRect() | ctx.strokeRect(x, y, w, h) | Quick outlined rectangles (no fill needed) | No | Yes | Yes (auto) |
| rect() + fill()/stroke() | ctx.rect(x,y,w,h); ctx.fill() | When you want both fill + stroke, or need to combine with other path commands | Optional | Optional | Yes (manual) |
| roundRect() (modern) | ctx.roundRect(x,y,w,h, radius) | Rounded corners (Chrome/Edge 2023+, Firefox 2024+, Safari 2024+) | Optional | Optional | Yes (manual) |
Best practice in 2026 → Use fillRect() or strokeRect() when you just need a simple rectangle → Use rect() + fill()/stroke() when you need both fill and stroke or want to combine with lines/arcs
3. Minimal complete example – All four methods side by side
Copy-paste and run this — it shows every rectangle style in one canvas with labels.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Canvas – All Rectangle Types</title> <style> canvas { border: 1px solid #ccc; background: #f8f9fa; display: block; margin: 40px auto; } </style> </head> <body> <canvas id="c" width="900" height="500"></canvas> <script> const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d'); ctx.font = 'bold 18px Arial'; ctx.textAlign = 'center'; ctx.fillStyle = '#333'; // ─── 1. Simple filled rectangle (fillRect) ctx.fillStyle = '#4CAF50'; ctx.fillRect(80, 80, 180, 120); ctx.fillText('fillRect (filled only)', 170, 230); // ─── 2. Simple outlined rectangle (strokeRect) ctx.strokeStyle = '#F44336'; ctx.lineWidth = 10; ctx.strokeRect(340, 80, 180, 120); ctx.fillText('strokeRect (outline only)', 430, 230); // ─── 3. Both fill + stroke using rect() + fill() + stroke() ctx.beginPath(); ctx.rect(600, 80, 180, 120); // defines the path ctx.fillStyle = '#2196F3'; ctx.fill(); // fill inside ctx.strokeStyle = '#0D47A1'; ctx.lineWidth = 8; ctx.stroke(); // outline on top ctx.fillText('rect() + fill() + stroke()', 690, 230); // ─── 4. Rounded rectangle (modern roundRect) ctx.beginPath(); ctx.roundRect(80, 280, 180, 120, 30); // last number = corner radius ctx.fillStyle = '#FF9800'; ctx.fill(); ctx.strokeStyle = '#EF6C00'; ctx.lineWidth = 10; ctx.stroke(); ctx.fillText('roundRect (rounded corners)', 170, 430); // Bonus – different radius on each corner (modern browsers) ctx.beginPath(); ctx.roundRect(340, 280, 180, 120, [20, 40, 60, 80]); // top-left, top-right, bottom-right, bottom-left ctx.fillStyle = '#673AB7'; ctx.fill(); ctx.strokeStyle = '#512DA8'; ctx.lineWidth = 8; ctx.stroke(); ctx.fillText('roundRect with per-corner radius', 430, 430); </script> </body> </html> |
What you should see & remember forever:
- Green rectangle → filled only (fillRect)
- Red rectangle → outlined only (strokeRect)
- Blue rectangle → filled AND outlined (rect() + fill() + stroke())
- Orange rectangle → rounded corners (roundRect with single radius)
- Purple rectangle → different radius per corner (modern feature)
Very important order rule When you want both fill + stroke: → fill() first → stroke() second Stroke draws on top of fill — if you stroke first, fill will cover half the line thickness.
4. Quick reference – Rectangle commands cheat sheet
| Goal | Code pattern (after getting ctx) | Notes / Gotchas |
|---|---|---|
| Filled rectangle | ctx.fillStyle = ‘#2196F3’; ctx.fillRect(x,y,w,h) | Fastest for solid fills |
| Outlined rectangle | ctx.strokeStyle = ‘#0D47A1’; ctx.lineWidth=8; ctx.strokeRect(x,y,w,h) | No fill — only border |
| Both fill + stroke | ctx.beginPath(); ctx.rect(x,y,w,h); ctx.fill(); ctx.stroke() | Use this when you need control or combine with arcs |
| Rounded corners (modern) | ctx.roundRect(x,y,w,h, radius) | Works in Chrome/Edge 2023+, Firefox 2024+, Safari 2024+ |
| Different radius per corner | ctx.roundRect(x,y,w,h, [tl, tr, br, bl]) | tl = top-left, tr = top-right, etc. |
5. Your three tiny practice tasks (10–15 minutes each)
Task 1 – Flag with rectangle Draw a rectangle background (any color) Put a smaller white rectangle in the center Put a small red circle in the center of the white rectangle
Task 2 – Photo frame Draw a big gray rectangle Inside it draw a smaller white rectangle with thick black stroke Add rounded corners (try roundRect or manual arcs)
Task 3 – Progress bar Draw a gray background rectangle On top draw a green filled rectangle that is only 60% wide (simulate progress)
Paste any of them here when you finish — I’ll review it like we’re pair-programming together.
──────────────────────────────
Which part still feels a little confusing?
- Difference between fillRect vs rect + fill()?
- Why stroke order matters when doing both fill + stroke?
- How to make rounded rectangles without roundRect?
- Per-corner radius trick?
- Something else?
Tell me — we’ll stay on rectangles until you feel super confident drawing and combining them with other shapes.
You’re doing really well — rectangles are the foundation of almost every UI element and layout in Canvas! 🚀
