Icons Sizing

Sizing & stroke weight

Every icon is drawn on a 24 × 24 viewBox. Gazelle defines the line weight it wants to see at each of four sizes and back-solves the stroke-width attribute from it — a hand-tuned optical scale, not a formula.

The scale stroke-width = line × 24 ÷ size

Stroke width is measured in viewBox units, not pixels, so the attribute alone tells you nothing about how heavy an icon looks — a constant 1.5 renders a 1 px line at 16 px and a 2 px line at 32 px. The weights below are the rendered ones; the attribute follows from the size. Note that larger icons take a relatively finer line, which is what stops a 64 px icon reading as bold.

16 px → 1 px line stroke-width 1.5
Inline with 12–14 px text, dense tables
24 px → 1 px line default stroke-width 1
Navigation, standalone actions, 16–18 px text
32 px → 1.25 px line stroke-width 0.9375
Feature callouts, empty states, headings
48 px → 1.75 px line stroke-width 0.875
Feature tiles, onboarding, large empty states
64 px → 2.1 px line stroke-width 0.7875
Hero moments, illustration, marketing
16 = calc(4 × var(--spacing)) 24 = calc(6 × var(--spacing)) 32 = calc(8 × var(--spacing)) 48 = calc(12 × var(--spacing)) 64 = calc(16 × var(--spacing))

Only these five sizes have a defined weight. There is no dedicated icon-size token yet — the sizes are steps on the 4 px spacing grid the rest of the system is built on.

ColourcurrentColor

Icons inherit the text colour they sit next to. Set color on the parent rather than a stroke on the SVG, so an icon in a --color-fg-muted paragraph mutes with it.

Optical size24 × 24

Keep the 24 × 24 viewBox and change width/height plus stroke-width. Cropping the viewBox breaks the shared optical margin between icons.

Labellingaria-hidden

Decorative icons take aria-hidden="true". An icon that is the only content of a control needs an aria-label on the control itself.