Canvas Fill and Stroke

fillStyle and strokeStyle set the paint canvas uses, while fill() paints a shape's interior and stroke() paints only its outline.

Two Ways to Paint a Shape

Every path you build with moveTo()/lineTo()/arc() and similar methods can be rendered in two different ways. fill() treats the path as the boundary of a shape and paints every pixel inside that boundary using the current fillStyle. stroke() instead paints a line that traces the path itself using strokeStyle and lineWidth, leaving the interior untouched. Nothing stops you from calling both on the same path to get a filled shape with a visible outline.

fillStyle and strokeStyle

fillStyle and strokeStyle are context properties, not method arguments - you set them once and they apply to every fill() or stroke() call made afterward, until you change them again. Both properties accept anything CSS accepts for a color: keywords like "tomato", hex codes like "#ff6347", rgb()/rgba() functions, hsl() functions, and even gradient or pattern objects created with createLinearGradient(), createRadialGradient(), or createPattern().

  • fillStyle / strokeStyle accept hex codes, named colors, rgb()/rgba(), hsl(), gradients, and patterns.
  • fill() paints the inside of the current path using fillStyle; it treats an open path as closed for this purpose.
  • stroke() paints a line following the current path using strokeStyle and lineWidth.
  • Calling both fill() and stroke() on the same path draws a filled shape with an outline.
  • The default fillStyle and strokeStyle are both solid black ("#000000").

Example

<!DOCTYPE html>
<html>
<body>

<canvas id="fillVsStroke" width="320" height="140"></canvas>

<script>
  const ctx = document.getElementById("fillVsStroke").getContext("2d");

  ctx.beginPath();
  ctx.rect(20, 20, 100, 100);
  ctx.fillStyle = "mediumseagreen";
  ctx.fill();

  ctx.beginPath();
  ctx.rect(160, 20, 100, 100);
  ctx.strokeStyle = "mediumseagreen";
  ctx.lineWidth = 4;
  ctx.stroke();
</script>

</body>
</html>

Layering Fill and Stroke

Note: When a shape needs both fill and stroke, call fill() before stroke(). A stroked line straddles the path evenly on both sides, so stroking first and filling second can paint over the inner half of the outline.

Example

<!DOCTYPE html>
<html>
<body>

<canvas id="gradientFill" width="300" height="120"></canvas>

<script>
  const ctx = document.getElementById("gradientFill").getContext("2d");
  const gradient = ctx.createLinearGradient(0, 0, 300, 0);
  gradient.addColorStop(0, "#ff7e5f");
  gradient.addColorStop(1, "#feb47b");

  ctx.beginPath();
  ctx.rect(10, 10, 280, 100);
  ctx.fillStyle = gradient;
  ctx.fill();
</script>

</body>
</html>

Example

<!DOCTYPE html>
<html>
<body>

<canvas id="filledCircle" width="200" height="200"></canvas>

<script>
  const ctx = document.getElementById("filledCircle").getContext("2d");

  ctx.beginPath();
  ctx.arc(100, 100, 70, 0, Math.PI * 2);
  ctx.fillStyle = "lightskyblue";
  ctx.fill();
  ctx.strokeStyle = "navy";
  ctx.lineWidth = 6;
  ctx.stroke();
</script>

</body>
</html>
Note: fill() treats an open path as if it were closed purely for the purpose of deciding what counts as "inside", without adding a permanent segment to the path. If you then call stroke() on that same open path, the closing edge will not be outlined unless you called closePath() yourself.
MethodPurpose
fill()Paints the interior area enclosed by the path, using fillStyle
stroke()Paints a line traced along the path, using strokeStyle and lineWidth
fillStyleColor, gradient, or pattern used by fill()
strokeStyleColor, gradient, or pattern used by stroke()
closePath()Adds a real segment back to the path's start, affecting both fill() and stroke()

Exercise: Canvas Fill and Stroke

What is the default fillStyle color if none has been set?