SVG fill and stroke: colour, width, dashes and opacity

In SVG, fill paints the inside of a shape and stroke paints its outline. The defaults, colour values, stroke-width, dashes, caps, joins and opacity.

Published

In an SVG, fill sets the colour inside a shape and stroke sets the colour of its outline. stroke-width sets how thick the outline is. The defaults are a black fill and no stroke, which is why a shape with no styling shows as solid black and a bare line does not show at all.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="40" fill="gold" stroke="black" stroke-width="4"/>
</svg>

The properties

PropertyWhat it setsDefault
fillColour of the insideblack
fill-opacityTransparency of the fill, 0 to 11
fill-ruleWhich enclosed areas count as inside: nonzero or evenoddnonzero
strokeColour of the outlinenone
stroke-widthThickness of the outline1
stroke-opacityTransparency of the outline, 0 to 11
stroke-linecapShape of line ends: butt, round, squarebutt
stroke-linejoinShape of corners: miter, round, bevelmiter
stroke-dasharrayPattern of dashes and gapsnone
stroke-dashoffsetWhere along the line the dash pattern starts0

Each can be written as an attribute (fill="gold"), in a style attribute, or in CSS. Children inherit them, so setting fill on a <g> or on the <svg> colours everything inside that has no fill of its own.

Colour values

fill and stroke accept the same values:

  • A name: red, gold, teal.
  • Hex: #f60 or #ff6600.
  • A function: rgb(255, 102, 0), and in browsers hsl(24, 100%, 50%) too.
  • none: paint nothing.
  • currentColor: use the text colour of the surrounding page, the basis of recolouring an SVG with CSS.
  • url(#id): a gradient or pattern defined elsewhere in the file.

No fill, and a transparent fill

For an outline only, use fill="none". fill="transparent" looks the same in a browser, with one difference: a transparent fill still counts as part of the shape for clicks and hover, and none does not. For a button outline that should react anywhere inside it, use transparent. For files going to other software, use none, which everything understands.

To make a fill partly see-through:

<rect width="60" height="60" fill="navy" fill-opacity="0.5"/>

fill-opacity and stroke-opacity affect one part each. opacity fades the whole element, fill and stroke together. Browsers also accept transparency inside the colour, as in #00008080 or rgb(0 0 128 / 50%), but vector editors and machine software often do not, so the separate opacity attributes are the safer choice in a file.

Stroke width

stroke-width is measured in the drawing’s own units, not screen pixels. In an icon with viewBox="0 0 24 24", a stroke width of 2 is one twelfth of the icon’s width, whatever size the icon is shown at. Show it at 48 pixels and the line is 4 pixels thick. SVG viewBox explained covers the scaling.

To keep a line the same thickness on screen however the drawing is scaled, add vector-effect="non-scaling-stroke" to the shape.

The stroke is centred on the outline: half lies inside the shape and half outside. Two consequences:

  • A shape that touches the edge of the viewBox has the outer half of its stroke cut off. A circle of radius 50 in a 100 unit viewBox needs to shrink to radius 48 to fit a stroke of 4.
  • With a partly transparent stroke, the fill shows through the inner half.

Stroke inside or outside

SVG has no working setting to put the stroke fully inside or outside a shape. Two workarounds:

Outside: paint-order="stroke" paints the stroke first and the fill on top, hiding the inner half. Double the stroke width to make up for it. This needs an opaque fill.

Inside: double the stroke width and clip the shape to its own outline, which hides the outer half:

<clipPath id="inside"><circle cx="50" cy="50" r="40"/></clipPath>
<circle cx="50" cy="50" r="40" fill="gold" stroke="black" stroke-width="8" clip-path="url(#inside)"/>

Caps and joins

stroke-linecap shapes the two ends of an open line. butt stops dead at the end point. round and square both extend past it by half the stroke width, with a rounded or a squared end.

stroke-linejoin shapes corners. miter gives a sharp point, round a rounded one, and bevel a flattened one. On a very sharp corner a mitre would stick out a long way, so stroke-miterlimit (4 by default) turns any corner sharper than about 29 degrees into a bevel. If a spike in a star or a letter looks clipped, raise the limit or use round.

Dashes

stroke-dasharray lists dash and gap lengths in turn, in the same units as the stroke width.

ValueResult
8 4Dashes of 8 with gaps of 4
4Dashes of 4 with gaps of 4
10 3 2 3Long dash, gap, short dash, gap
0 6 with stroke-linecap="round"Round dots, 6 apart

stroke-dashoffset slides the pattern along the line. Animating it is how the “line drawing itself” effect is made: set one dash as long as the whole path, offset it by the same amount, and animate the offset to zero.

Fill rule

When a path crosses itself or holds one outline inside another, fill-rule decides which areas are filled. evenodd makes every second nested area a hole. The default, nonzero, makes a hole only where the inner outline runs in the opposite direction. The path guide explains outlines and holes.

An open path can be filled too. The fill behaves as if a straight line joined the end back to the start, which is why a curved line with no fill="none" shows an unexpected black segment.

For cutting machines and lasers

Most cutting and plotting software follows the path itself and ignores the stroke’s width: a line with a stroke 10 mm thick is still cut as one line down its middle. Colours are used to sort shapes into layers or, in laser software, into operations such as cut and engrave. To cut the visible outline of a thick line or of outlined lettering, convert the stroke into a shape first. In Inkscape that is Path, Stroke to Path. In Illustrator it is Object, Path, Outline Stroke.

Common problems

What you seeCauseFix
The shape is solid blackNo fill given, so the default appliesSet fill, or fill="none"
A line or path is invisibleNo stroke givenSet stroke
The outline is cut off at the edgesHalf the stroke lies outside the viewBoxMove the shape in by half the stroke width, or enlarge the viewBox
The line is thicker or thinner than expectedStroke width scales with the viewBoxChange stroke-width, or use non-scaling-stroke
A black wedge across a curved lineThe open path is filledfill="none"
Sharp points look chopped offMitre limitRaise stroke-miterlimit or use stroke-linejoin="round"
CSS fill has no effectThe shape carries its own value, or the SVG is in an <img>See changing SVG colour with CSS

Questions

Can a stroke have a gradient? Yes. stroke="url(#id)" works the same as for a fill.

What is the difference between opacity and fill-opacity? opacity fades the whole element as one. fill-opacity fades only the fill and leaves the stroke solid.

Can one shape have two strokes? Not directly. Draw the shape twice, the lower copy with a wider stroke.