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
| Property | What it sets | Default |
|---|---|---|
fill | Colour of the inside | black |
fill-opacity | Transparency of the fill, 0 to 1 | 1 |
fill-rule | Which enclosed areas count as inside: nonzero or evenodd | nonzero |
stroke | Colour of the outline | none |
stroke-width | Thickness of the outline | 1 |
stroke-opacity | Transparency of the outline, 0 to 1 | 1 |
stroke-linecap | Shape of line ends: butt, round, square | butt |
stroke-linejoin | Shape of corners: miter, round, bevel | miter |
stroke-dasharray | Pattern of dashes and gaps | none |
stroke-dashoffset | Where along the line the dash pattern starts | 0 |
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:
#f60or#ff6600. - A function:
rgb(255, 102, 0), and in browsershsl(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.
| Value | Result |
|---|---|
8 4 | Dashes of 8 with gaps of 4 |
4 | Dashes of 4 with gaps of 4 |
10 3 2 3 | Long 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 see | Cause | Fix |
|---|---|---|
| The shape is solid black | No fill given, so the default applies | Set fill, or fill="none" |
| A line or path is invisible | No stroke given | Set stroke |
| The outline is cut off at the edges | Half the stroke lies outside the viewBox | Move the shape in by half the stroke width, or enlarge the viewBox |
| The line is thicker or thinner than expected | Stroke width scales with the viewBox | Change stroke-width, or use non-scaling-stroke |
| A black wedge across a curved line | The open path is filled | fill="none" |
| Sharp points look chopped off | Mitre limit | Raise stroke-miterlimit or use stroke-linejoin="round" |
CSS fill has no effect | The 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.