Drawing and Styling Text on the HTML Canvas

January, 7th 2025 4 min read

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:

  1. a visible <canvas> element in the DOM
  2. a rendering context retrieved via JavaScript

Here is a minimal setup:

html
<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:

js
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:

html
<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:

js
ctx.textAlign = "center";

textBaseline

Controls vertical alignment relative to (x, y):

  • "top"
  • "hanging"
  • "middle"
  • "alphabetic" (default)
  • "ideographic"
  • "bottom"

Example:

js
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:

js
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

js
ctx.fillStyle = "#0055ff";
ctx.strokeStyle = "#333";
ctx.lineWidth = 2;

Shadows

Canvas can draw soft shadows behind text:

js
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:

js
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:

js
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:

js
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

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