Drawing and Styling Text on the HTML Canvas
The HTML canvas element provides a low‑level, immediate‑mode drawing environment for building visual interfaces, animations, and games. Among its features is the ability to draw text directly onto the pixel buffer using the CanvasRenderingContext2D API. Unlike standard HTML text, canvas text is not part of the document flow, cannot be selected, and must be redrawn whenever the scene changes.
This article explains how canvas text rendering works, how to structure a basic drawing setup, and how to control alignment, baselines, color, and font settings. The goal is to show not just the syntax but the reasoning behind each property and how to achieve predictable results across browsers.
1. Setting Up a Canvas for Text Rendering
A canvas requires two things:
- a visible
<canvas>element in the DOM - a rendering context retrieved via JavaScript
Here is a minimal setup:
<canvas id="textCanvas" width="400" height="200"></canvas>Always set width and height as attributes, not CSS styles. CSS scaling changes appearance and pixel density, while attributes define the actual drawing resolution.
Access the drawing context:
const canvas = document.getElementById("textCanvas");
const ctx = canvas.getContext("2d");Now the canvas is ready for drawing commands.
2. Rendering Basic Text with fillText and strokeText
Canvas provides two primary text functions:
- fillText(text, x, y) — draws filled text
- strokeText(text, x, y) — draws outlined text
Here is the full working example combining both:
<canvas id="textCanvas" width="400" height="200" style="border:1px solid #333;"></canvas>
<script>
const canvas = document.getElementById("textCanvas");
const ctx = canvas.getContext("2d");
ctx.font = "24px Arial";
ctx.fillStyle = "blue";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Hello, Canvas!", canvas.width / 2, canvas.height / 2);
ctx.strokeStyle = "red";
ctx.lineWidth = 1.5;
ctx.strokeText("Outline Example", canvas.width / 2, canvas.height / 2 + 30);
</script>This example demonstrates the two fundamental text rendering methods canvas provides.
3. Understanding Text Positioning: Alignment and Baselines
Canvas text positioning differs from HTML. Canvas always draws text relative to a single coordinate point.
textAlign
Controls horizontal alignment relative to (x, y):
-
"left" -
"right" -
"center" -
"start" -
"end"
Example:
ctx.textAlign = "center";textBaseline
Controls vertical alignment relative to (x, y):
-
"top" -
"hanging" -
"middle" -
"alphabetic"(default) -
"ideographic" -
"bottom"
Example:
ctx.textBaseline = "middle";Choosing the right combination provides predictable alignment, especially when centering elements or building UI widgets.
4. Customizing Fonts and Rendering Behavior
Canvas text rendering uses a CSS‑style font string:
ctx.font = "italic bold 20px Verdana";This string must contain at least a font size and family. The browser handles font loading, so if a custom web font is used, ensure it loads before drawing.
Fill and stroke styles
ctx.fillStyle = "#0055ff";
ctx.strokeStyle = "#333";
ctx.lineWidth = 2;Shadows
Canvas can draw soft shadows behind text:
ctx.shadowColor = "rgba(0,0,0,0.4)";
ctx.shadowBlur = 4;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;Shadows impact performance, but they can be valuable when rendering UI elements, labels, or title screens.
5. Multi‑Line Text Strategies
Canvas does not support multi‑line text natively. You must break lines manually:
function drawMultiline(ctx, text, x, y, lineHeight) {
const lines = text.split("\n");
lines.forEach((line, i) => {
ctx.fillText(line, x, y + i * lineHeight);
});
}This technique is essential when rendering paragraphs, tooltips, or wrapped labels.
6. Measuring Text Before Drawing
Canvas provides measureText() to calculate text widths before rendering:
const metrics = ctx.measureText("Hello");
console.log(metrics.width);This is useful for:
- centering text manually
- calculating wrapping
- positioning text relative to rectangles or buttons
7. Redrawing Text in Animated or Interactive Scenes
Because canvas is bitmap‑based, text must be redrawn whenever:
- the scene changes
- the canvas is resized
- animations run
- dynamic UI updates occur
Typical redraw cycle:
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillText("Frame " + performance.now(), 200, 100);
requestAnimationFrame(render);
}
render();This differs from HTML layout, where text persists without manual management.
8. Complete Example with Multiple Text Styles
<canvas id="demo" width="500" height="250"></canvas>
<script>
const c = document.getElementById("demo");
const ctx = c.getContext("2d");
ctx.fillStyle = "#222";
ctx.font = "28px Georgia";
ctx.fillText("Canvas Text Basics", 20, 40);
ctx.strokeStyle = "#cc0000";
ctx.font = "24px Arial";
ctx.strokeText("Outlined Example", 20, 100);
ctx.font = "20px Verdana";
ctx.shadowBlur = 5;
ctx.shadowColor = "rgba(0,0,0,0.5)";
ctx.fillText("Shadowed text for UI widgets", 20, 160);
</script>This demonstrates filled, stroked, and shadowed text in a single composition.
Conclusion
Drawing text on an HTML canvas is more than calling fillText(). Once you understand alignment, baselines, font rules, measurement, and redraw behavior, canvas becomes a flexible environment for UI elements, visualizations, and game interfaces. Because text becomes part of a pixel buffer, you gain more control over styling and rendering but must manage layout manually. With these techniques, you can build reliable, visually consistent text rendering for any canvas‑based project.