Strokes or fills? Outlining icons for production
Stroke-based versus fill-based SVG icons, why logo sets outline their strokes, and what non-scaling-stroke does to recoloring and scaling.
5 min read
A line in an SVG icon can be drawn two ways: as a path with a stroke, or as a closed outline with a fill. On screen they can look identical. In production they behave differently when you scale, recolor, convert or optimize the icon, which is why logo libraries almost always ship outlined, fill-only artwork, while some interface icon sets deliberately keep their strokes.
The same line, drawn twice
Here is a short horizontal bar with rounded ends, drawn as a stroke:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M4 12h16" stroke="#a1a1aa" stroke-width="2" stroke-linecap="round" fill="none"/>
</svg>
And the same bar as a filled outline:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M4 11h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z" fill="#a1a1aa"/>
</svg>
The stroked version describes a centerline and asks the renderer to paint 1 unit on either side, with round caps. The filled version spells out the resulting shape: top edge, right cap, bottom edge, left cap. "Outlining" or "expanding" a stroke is the design tool doing that conversion for you.
How strokes scale
stroke-width is measured in the same user units as the viewBox. When the icon scales, the stroke scales with it, exactly like a fill would. A 2-unit stroke on a 24-unit grid renders at:
| Display size | Rendered stroke width |
|---|---|
| 16 px | 1.33 px |
| 24 px | 2 px |
| 32 px | 2.67 px |
| 48 px | 4 px |
So for plain scaling, strokes and fills behave the same. The proportions of the drawing are preserved either way. The differences lie elsewhere.
Why logo sets outline their strokes
Rendering is fully determined. A stroke is a set of instructions (width, caps, joins, miter limit, dashes) that every renderer has to interpret. Sharp corners are the classic trouble spot: whether a join is drawn mitered or falls back to a bevel depends on stroke-miterlimit, and tools have not always handled these attributes identically. An outline is just a shape, and every renderer fills a shape the same way.
Design-tool stroke alignment does not exist in SVG. Figma, Illustrator and Sketch let you put a stroke inside, centered on, or outside a path. SVG strokes are always centered. Exporting an inside or outside stroke means the tool has to emulate it, often with a clip path or mask and a doubled stroke width. Outlining first gives you a clean shape instead.
Recoloring touches one property. A fill-only icon changes color by changing fill. An icon that mixes fills and strokes needs both changed. A common bug: a mono icon set with fill="currentColor" on the root <svg>, where one detail is a stroke with a hard-coded color, so that detail ignores the theme. CSS mask recoloring, which uses only the icon's silhouette, works with both, but currentColor and CSS fill rules need every part covered.
Strokes overhang the geometry. Half of a centered stroke sits outside the path. A shape that touches the edge of the viewBox loses that outer half to clipping, and a bounding box measured from the path (as getBBox() does) is smaller than what is painted. Outlined shapes are exactly as big as they look.
Some destinations only understand fills. Icon fonts, for example, are made of filled outlines; there is no stroke in a glyph. Some converters and importers handle strokes poorly or not at all. A fill-only file goes through all of them.
The brand's weights are frozen. A logo's line weight is part of the mark. Outlining locks it in, so nobody accidentally "adjusts" it later by changing a single attribute.
When to keep strokes
Strokes are not a mistake. They are the right choice when the stroke weight is a parameter you want to control:
- Interface icon sets drawn as line icons, where the whole set uses one stroke width on a shared grid and you may want a lighter or heavier variant by changing one number. Stroke weight consistency covers how that weight relates to the brand logos sitting next to them.
- Charts, diagrams and connectors, where lines should stay a fixed thickness however large the drawing is.
- Line-drawing animations, which animate
stroke-dasharrayandstroke-dashoffsetalong a path. That trick only exists for strokes.
For icons that follow text color, keep strokes as stroke="currentColor" in the same way fills use fill="currentColor". currentColor in SVG explains how that inheritance works.
vector-effect: non-scaling-stroke
Sometimes you want the opposite of normal scaling: a 1.5 px line at every size. vector-effect="non-scaling-stroke" does that. The stroke width is applied in screen pixels after all transforms, including the viewBox scaling:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M3 17l6-6 4 4 8-8" fill="none" stroke="currentColor"
stroke-width="1.5" vector-effect="non-scaling-stroke"/>
</svg>
| Display size | Normal stroke (1.5 units) | Non-scaling stroke (1.5) |
|---|---|---|
| 16 px | 1 px | 1.5 px |
| 24 px | 1.5 px | 1.5 px |
| 48 px | 3 px | 1.5 px |
| 96 px | 6 px | 1.5 px |
That is ideal for a sparkline, a chart axis or a map route that is resized with its container. It is wrong for logos. The relationship between stroke and shape is part of the design, and a non-scaling stroke makes a mark look heavy when small and spindly when large. It also means the icon is no longer self-contained: its appearance depends on the size it is displayed at.
Outlining for production
A practical workflow for a logo or icon library:
- Keep an editable source. Store the stroked original in your design file or source folder. Outlining is one-way; you cannot get the centerline back afterwards.
- Outline on export. Most tools have a command for it: Outline Stroke in Figma and Illustrator, Stroke to Path in Inkscape.
- Unite overlapping pieces. Outlined strokes often leave several overlapping shapes. With an opaque fill, that is invisible. With partial opacity, or a mono version recolored to a translucent color, the overlaps show up darker. A boolean union merges them into one outline.
- Check holes and direction. Outlining a closed stroke (such as a ring) produces a shape with a hole. Make sure the hole survives under both fill rules; see fill-rule: nonzero vs evenodd.
- Compare sizes. Outlined round caps and joins add curve segments, so the file can grow a little. That is normal. A large jump usually means the tool approximated curves with many short segments; try simplifying the path.
The result is a file that looks the same in every browser, design tool and converter, and recolors by changing a single fill.