W3docs

SVG Stroking

Learn the SVG stroke properties with runnable examples: stroke, stroke-width, stroke-linecap, stroke-linejoin, stroke-dasharray, stroke-dashoffset and more.

Styling SVG outlines with stroke properties

The stroke of an SVG element is the paint applied along the outline of a shape, line, or text — as opposed to the fill, which paints the interior. SVG gives you a family of stroke-* properties that control every aspect of that outline: its color, thickness, transparency, how its ends are capped, how its corners are joined, and whether it is solid or dashed.

These properties are presentation attributes, so you can set them either directly on an element (stroke="purple") or through CSS (stroke: purple;). They also inherit, which is why it is common to set them once on a <g> (group) element and let the child shapes pick them up.

This chapter covers the full set of stroke properties. For the shapes you will be stroking, see SVG Path, SVG Line, and SVG Text. If you are new to SVG, start with the SVG Introduction, and keep the SVG Reference handy for a quick lookup of every attribute.

The stroke properties at a glance:

  • stroke — the color (or other paint) of the outline.
  • stroke-width — the thickness of the outline.
  • stroke-opacity — how transparent the stroke is, from 0 to 1.
  • stroke-linecap — the shape drawn at the open ends of a line: butt, round, or square.
  • stroke-linejoin — the shape drawn where two line segments meet: miter, round, or bevel.
  • stroke-miterlimit — how far a miter join may extend before it falls back to a bevel.
  • stroke-dasharray — the pattern of dashes and gaps for a dashed outline.
  • stroke-dashoffset — how far along the path the dash pattern starts.

The stroke property

The stroke property sets the color of the outline. It accepts any CSS color value — a named color, a hex code, rgb(), hsl(), or a reference to a gradient or pattern. By default shapes have no stroke (none), so nothing is drawn until you set one.

In the example below, fill="none" is set on the group so only the outlines are visible, and each path is stroked in a different color.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="250" height="100">
      Sorry, your browser doesn't support inline SVG.
      <g fill="none">
        <path stroke="purple" d="M5 30 l215 0" />
        <path stroke="lightgreen" d="M5 60 l215 0" />
        <path stroke="pink" d="M5 90 l215 0" />
      </g>
    </svg>
  </body>
</html>

The text "Sorry, your browser doesn't support inline SVG." is fallback content. It must be a direct text child of the <svg> element so that a browser without inline-SVG support shows it instead of the graphic. Modern browsers ignore it and render the SVG.

The stroke-width property

The stroke-width property sets the thickness of the outline. The stroke is drawn centered on the path, so half of its width sits on each side of the geometric line.

A number on its own is interpreted in user units (the SVG coordinate system) — stroke-width="5" and stroke-width="5px" are equivalent in a plain SVG. You may also use explicit CSS units (px, em, pt) or a percentage, which is resolved against the diagonal of the SVG viewport rather than its width or height.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="250" height="100">
      <g fill="none" stroke="lightgreen">
        <path stroke-width="3" d="M5 30 l215 0" />
        <path stroke-width="5" d="M5 60 l215 0" />
        <path stroke-width="7" d="M5 90 l215 0" />
      </g>
    </svg>
  </body>
</html>

The stroke-opacity property

The stroke-opacity property controls the transparency of the stroke alone, independent of the fill's opacity. It takes a number from 0 (fully transparent) to 1 (fully opaque); a value like 0.5 makes the stroke half-transparent. This is useful for layering outlines or letting the background show through an outline without affecting the shape's fill.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="250" height="100">
      <g fill="none" stroke="purple" stroke-width="8">
        <path stroke-opacity="1" d="M5 30 l215 0" />
        <path stroke-opacity="0.5" d="M5 60 l215 0" />
        <path stroke-opacity="0.2" d="M5 90 l215 0" />
      </g>
    </svg>
  </body>
</html>
Result

The stroke-linecap property

The stroke-linecap property defines the shape drawn at the open ends of a stroked path. It accepts three values:

  • butt (the default) — the stroke stops exactly at the path's endpoint with a flat edge and no extension. The drawn length equals the geometric length of the path.
  • round — a semicircle whose radius is half the stroke width is added at each end, so the line extends past the endpoint by stroke-width / 2 and ends in a soft curve.
  • square — a flat cap is added that extends past the endpoint by stroke-width / 2. It looks like butt but is longer; the extra length on each end is the same as round, only with a flat edge instead of a curved one.

The difference is most visible with a thick stroke. Notice how the round and square lines below appear slightly longer than the butt line even though all three paths share the same coordinates.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="250" height="100">
      <g fill="none" stroke="lightblue" stroke-width="10">
        <path stroke-linecap="butt" d="M5 30 l215 0" />
        <path stroke-linecap="round" d="M5 60 l215 0" />
        <path stroke-linecap="square" d="M5 90 l215 0" />
      </g>
    </svg>
  </body>
</html>

The stroke-linejoin property

The stroke-linejoin property defines the shape used where two line segments of a path meet — the corners. It accepts three common values:

  • miter (the default) — the outer edges of the two segments are extended until they meet in a sharp point.
  • round — the corner is rounded off with an arc.
  • bevel — the corner is cut off with a flat edge.
<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="250" height="120">
      <g fill="none" stroke="orange" stroke-width="12">
        <path stroke-linejoin="miter" d="M15 90 L40 20 L65 90" />
        <path stroke-linejoin="round" d="M105 90 L130 20 L155 90" />
        <path stroke-linejoin="bevel" d="M185 90 L210 20 L235 90" />
      </g>
    </svg>
  </body>
</html>
Result

The stroke-miterlimit property

When stroke-linejoin is miter, very sharp angles can produce extremely long, spiky points. The stroke-miterlimit property caps how long such a point may get. It sets the maximum allowed ratio of the miter length to the stroke width, where the miter length is the distance from the inner corner to the outer tip of the point. If a join's ratio would exceed the limit, that join silently falls back to a bevel.

The default is 4, meaning a miter may stretch up to four times the stroke width before it is cut off (this preserves the point for any corner angle of about 29° or wider). The sharper the corner, the longer the miter, so the lower you set the limit, the wider the angle at which corners begin to bevel. A limit of 1 bevels almost every corner that is not a straight line; a large limit like 10 lets even very sharp spikes through. The value must be at least 1.

In the example below both paths form the same sharp peak, but the left one (stroke-miterlimit="1") is forced to a bevel while the right one (stroke-miterlimit="10") keeps its point.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="250" height="120">
      <g fill="none" stroke="purple" stroke-width="10" stroke-linejoin="miter">
        <path stroke-miterlimit="1" d="M20 100 L45 25 L70 100" />
        <path stroke-miterlimit="10" d="M120 100 L145 25 L170 100" />
      </g>
    </svg>
  </body>
</html>
Result

The stroke-dasharray property

The stroke-dasharray property turns a solid outline into a dashed one. Its value is a comma- or space-separated list of numbers that describe the lengths of dashes and gaps, applied in alternating order along the path:

  • A single value like stroke-dasharray="10" produces dashes and gaps of equal length (10,10).
  • Two values like stroke-dasharray="3,5" mean a 3-unit dash followed by a 5-unit gap, repeated.
  • With an even number of values, the list is used as-is and repeats.

If you supply an odd number of values, SVG repeats the list a second time to make it even, so the dash/gap roles alternate. For example, stroke-dasharray="30,15,10,10,10,15" reads as a 30-dash, 15-gap, 10-dash, 10-gap, 10-dash, 15-gap pattern, then cycles.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="250" height="100">
      <g fill="none" stroke="orange" stroke-width="5">
        <path stroke-dasharray="3,5" d="M5 30 l215 0" />
        <path stroke-dasharray="12,12" d="M5 60 l215 0" />
        <path stroke-dasharray="30,15,10,10,10,15" d="M5 90 l215 0" />
      </g>
    </svg>
  </body>
</html>

The stroke-dashoffset property

The stroke-dashoffset property shifts where the dash pattern begins along the path. A value of 0 (the default) starts the pattern at the path's start point; a positive value moves the starting point forward along the path, while a negative value moves it backward. This is what makes it possible to animate "marching ants" or line-drawing effects by gradually changing the offset.

In the example below all three lines share the same dash pattern but start it at different offsets, so the dashes appear shifted relative to one another.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="250" height="100">
      <g fill="none" stroke="lightgreen" stroke-width="5" stroke-dasharray="20,10">
        <path stroke-dashoffset="0" d="M5 30 l215 0" />
        <path stroke-dashoffset="10" d="M5 60 l215 0" />
        <path stroke-dashoffset="20" d="M5 90 l215 0" />
      </g>
    </svg>
  </body>
</html>
Result

Animating with stroke-dashoffset

Because the offset can be animated, stroke-dashoffset is the basis for two popular effects:

  • Marching ants — animate the offset through one full dash period so the dashes appear to crawl along the outline (like a selection marquee).
  • Line drawing — set stroke-dasharray to the path's total length so the whole path becomes one long dash, then animate the offset from that length down to 0 so the line appears to draw itself.

The CSS below produces the marching-ants effect. The animation runs from an offset of 0 to 30 (the length of one 15,15 dash-plus-gap cycle), which makes the loop seamless:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      .ants {
        stroke: purple;
        stroke-width: 3;
        fill: none;
        stroke-dasharray: 15, 15;
        animation: march 1s linear infinite;
      }
      @keyframes march {
        to {
          stroke-dashoffset: 30;
        }
      }
    </style>
  </head>
  <body>
    <svg width="220" height="120">
      <rect class="ants" x="10" y="10" width="200" height="100" />
    </svg>
  </body>
</html>
Result

For drawing whole shapes this way, see SVG Path and SVG Line; the full list of stroke attributes lives in the SVG Reference.

Practice

Practice
Which of the following statements is/are true about SVG stroking in HTML?
Which of the following statements is/are true about SVG stroking in HTML?
Was this page helpful?