---
name: iconography-and-imagery
description: Reference-grade guide to building and shipping icon systems (grids, optical sizing, variable axes, SVG delivery) and imagery (aspect ratios, art direction, modern formats, performance) with copy-pasteable code, exact numbers, and cross-device rules.
tags: [design-systems, icons, imagery, svg, illustration]
---
# Iconography & Imagery
Icons and images carry most of a UI's pixels and most of its weight. Get the grid, the optics, and the delivery format right and everything reads sharper and loads faster. This is the working reference: build the icon set on a disciplined grid, ship it as inline SVG or a sprite, and serve images as AVIF/WebP with a reserved aspect-ratio box.
## 1. Icon grid & construction
Every icon lives on a square pixel grid. Standardize one base, scale by clean multiples.
| Base grid | Used by | Live area (padding) | Stroke | Corner radius |
|-----------|---------|---------------------|--------|---------------|
| 16px | dense toolbars, inline text icons | 14px (1px) | 1.5px | 1px |
| 20px | compact UI (tables, menus) | 18px (1px) | 1.5px | 1.5px |
| **24px** | **default UI standard (Material)** | **20px (2px)** | **2px** | **2px** |
| 40px | large touch targets, feature tiles | 34px (3px) | 2.5px | 3px |
| 48px | hero / marketing | 40px (4px) | 3px | 4px |
**Keyline shapes** anchor optical consistency. In a 24px box the canonical keylines are: square 18×18, circle ⌀20, vertical rectangle 16×20, horizontal rectangle 20×16. Snap each glyph to the keyline that matches its dominant shape so a circle (◎) and a square (▣) feel the same visual weight even though their bounding boxes differ.
```
24px box, 2px padding → 20px live area
┌────────────────────────┐ ← 24px artboard
│ ┌──────────────────┐ │
│ │ keyline 20×20 │ │ ← optical balance happens HERE
│ │ ┌──────────┐ │ │
│ │ │ glyph │ │ │
│ │ └──────────┘ │ │
│ └──────────────────┘ │
└────────────────────────┘
```
**Rules**
- **Pixel-snap** all anchors to whole or half pixels at the base size. A 2px stroke centered on a whole-pixel coordinate renders crisp; a stroke on x=12.37 renders blurry. For odd stroke widths (1px) center on the *half*-pixel (x=12.5) so the stroke lands inside one pixel column; for even widths (2px) center on the whole pixel.
- **Optical alignment over mathematical centering.** A triangle (play ▶) centered by its bounding box looks left-heavy — nudge it ~1px right toward its visual centroid. Asymmetric glyphs almost always need a manual optical nudge.
- **Consistent corner radius** across the whole set. Don't mix 1px and 4px corners; pick one radius scaled per base size.
- **Terminal & joint consistency**: choose round vs. butt line caps and round vs. miter joins once (`stroke-linecap`, `stroke-linejoin`) and apply set-wide. Mismatched caps read as two different designers.
- **Optical sizing**: a stroke that reads as 2px at 24px becomes hairline at 16px and chunky at 48px. Maintain *apparent* weight by increasing relative stroke at small sizes and drawing dedicated small variants (don't just `transform: scale()` a 24px icon down to 16px — it goes muddy). Material ships 20/24/40/48 masters for exactly this reason.
## 2. Icon style systems
| Style | When | Notes |
|-------|------|-------|
| **Outline (stroke)** | default / idle states | lighter, modern, neutral; most flexible |
| **Filled (solid)** | selected / active / emphasis | higher contrast, signals "on" |
| **Duotone** | brand accent, illustrative chips | two opacities of one hue, or two tokens |
| **Two-tone / multicolor** | logos, status, rich UI | reserve for meaning, not decoration |
**The selected-state convention:** outline = inactive, filled = active. A tab bar shows outline icons; the current tab fills. This is learned, universal, and keeps you from inventing a new affordance.
**Material Symbols (variable font, 2024–2026)** exposes 4 axes — tune them with `font-variation-settings`, animate them with a transition:
```css
.material-symbols-outlined {
font-variation-settings:
'FILL' 0, /* 0 outline → 1 filled (animatable for select states) */
'wght' 400, /* 100–700 weight, match adjacent text weight */
'GRAD' 0, /* -25…200 emphasis; +50 on dark bg, -25 on light */
'opsz' 24; /* 20–48 OPTICAL SIZE — set to the rendered px size */
transition: font-variation-settings 200ms ease;
}
.nav-item[aria-current='page'] .material-symbols-outlined {
font-variation-settings: 'FILL' 1, 'wght' 500, 'GRAD' 0, 'opsz' 24;
}
```
> Always set `opsz` to the actual render size — that is what optical sizing is for. GRAD is a finer dial than wght for dark-mode legibility.
**SF Symbols (Apple platforms)** mirror SF font weights (`.ultraLight`…`.black`); pick the weight that matches the adjacent text. Rendering modes: **monochrome** (single tint), **hierarchical** (one hue, layered opacities), **palette** (you supply 2–3 colors), **multicolor** (built-in semantic colors, e.g. yellow warning). Align symbols to text via the SF baseline so glyph and label share a cap line.
## 3. Icon usage
- **Pair icons with labels.** Icon-only is only safe for the ~12 truly universal glyphs (search, close, menu, back, play). Everything else is a guessing game. Icon-only controls **must** carry an accessible name and ideally a tooltip:
```html
```
- **Size to cap-height, not line-height.** An inline icon next to 16px text should be ~16–20px (≈1em–1.25em) and vertically centered on the text's cap height. Match by eye — geometric icons often need to be slightly *larger* than the cap height to feel equal.
- **Color with `currentColor`** so icons inherit text color and theme automatically (see §4).
- **Touch target ≥ 44×44px (iOS) / 48×48dp (Android)** regardless of the glyph size. A 20px icon still needs 44px of hittable padding.
- **Avoid ambiguous metaphors**: a floppy disk for "save" survives only by convention; a heart vs. star vs. bookmark all mean "save for later" to different users — pick one and label it. Never overload one glyph with two meanings in the same product.
- **Recognizability ladder**: ~12 glyphs are truly universal (search, close ✕, menu ☰, back ‹, home, settings ⚙, share, trash, play/pause, plus, check, chevron). One tier down (filter, sort, sync, attach) is *familiar but not certain* — keep a label. Anything domain-specific (a custom "reconcile" icon) is decorative until proven; it never flies solo.
- **Direction & RTL**: mirror directional icons (back, next, list-indent, undo's curve) for right-to-left locales with `[dir="rtl"] .icon{ transform:scaleX(-1) }`; never mirror clocks, logos, or media-progress glyphs.
## 4. SVG delivery — the technical core
| Method | Best for | Color | Caching | Verdict |
|--------|----------|-------|---------|---------|
| **Inline `