SVG Fundamentals and Icon Systems
SVG (Scalable Vector Graphics) describes shapes, paths, and text using XML. Because it is resolution independent, the same file stays crisp on retina displays and when zoomed. That makes SVG the default choice for icons and logos on the modern web.
This learning activity covers core syntax, the coordinate system, how inline and external SVG differ for styling, and how to build reusable icon systems using <symbol>, <defs>, and sprite sheets.
Minimal Valid SVG
An SVG root element defines a viewport and optionally a viewBox that maps user coordinates onto that viewport.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" role="img" aria-labelledby="title-desc">
<title id="title-desc">Checkmark</title>
<path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
</svg>
-
xmlns: Required for standalone files; often implied when inline in HTML5. -
viewBox="min-x min-y width height": Defines the internal coordinate system; scaling preserves aspect ratio when paired withwidth/heightor CSS sizing. -
roleand<title>: Support accessibility when the graphic conveys meaning (more below).
Understanding viewBox
Think of viewBox as a window into a virtual canvas. The browser scales and translates that window to fit the SVG’s layout box (from attributes or CSS).
<!-- 24×24 "design grid"; path coordinates match this box -->
<svg viewBox="0 0 24 24"> ... </svg>
If you set only CSS width: 100% and height: auto with a viewBox, the graphic scales fluidly while keeping proportions. Without viewBox, scaling behavior is harder to predict.
Many icon sets use a 24×24 artboard. Keeping a consistent viewBox across your set makes alignment in buttons and navigation rows predictable.
Common SVG Elements (Icons)
Icons typically combine these building blocks:
-
<path>: Arbitrary shapes viad(path commands likeM,L,Z,C). -
<rect>,<circle>,<line>,<polyline>: Primitives for simple geometry. -
<g>: Groups elements; useful for transforms and targeting in CSS.
<svg viewBox="0 0 24 24" width="1em" height="1em" aria-hidden="true">
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/>
</svg>
Using currentColor for fill or stroke ties the icon to the CSS color property on an ancestor, which is ideal for theming.
Inline SVG vs External SVG
Inline (embedded in HTML)
- Pros: Style with CSS (including per-theme rules), animate parts, no extra request when the HTML is loaded.
- Cons: Repeating the same markup bloats HTML unless you use a component system or server includes.
External file (<img src="icon.svg">)
- Pros: Cacheable URL, simple drop-in, works like any image.
-
Cons: CSS in the main stylesheet cannot style the interior of the SVG when loaded this way (the document is a separate resource). You can still size the box and use
filteron theimgelement, but not target inner paths with CSS selectors.
<use> with symbols (icon system)
The pattern you will use for systems: define each icon once in a sprite, reference by ID. Styling options depend on whether you use shadow DOM considerations; for many teams, an inline sprite in the page or bundled SVG is still the most flexible.
If you need path-level styling from your app CSS, prefer inline SVG or tooling that inlines icons at build time. Do not expect img[src="...svg"] path { fill: red } to work across browsers.
Icon Systems: <symbol> and <use>
A sprite collects many icons in one SVG document. Each icon is stored as a <symbol> with an id and its own viewBox. Instances reference the symbol with <use href="#id"> (or xlink:href in older docs).
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;" aria-hidden="true">
<defs>
<symbol id="icon-home" viewBox="0 0 24 24">
<path fill="currentColor" d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
</symbol>
<symbol id="icon-search" viewBox="0 0 24 24">
<path fill="currentColor" d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0016 9.5 6.5 6.5 0 109.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
</symbol>
</defs>
</svg>
<!-- Instance: same document -->
<svg width="24" height="24" role="img" aria-labelledby="home-label">
<title id="home-label">Home</title>
<use href="#icon-home"/>
</svg>
The hidden sprite SVG is not displayed; it only holds definitions. Each visible <use> clones the symbol’s contents into the tree (with well-known caveats for deep styling in very old browsers; modern evergreen browsers handle this well for icons).
External sprite references
You can reference a symbol in another file: <use href="/icons/sprite.svg#icon-home">. Support is good in current browsers, but some teams prefer bundling one inline sprite to avoid extra round trips and fragment quirks.
Accessibility for Icons
-
Decorative: If the icon repeats text already on screen, hide it:
aria-hidden="true"and emptyaltforimg. -
Meaningful: Provide a name:
<title>inside the SVG witharia-labelledby, oraria-labelon a wrapping button/link, or visible text next to the icon. - Touch targets: Small icons in tappable areas should meet minimum size (often ~44×44 CSS px for mobile); expand hit area with padding rather than stretching the glyph awkwardly.
See WAI Images tutorial for decision trees that apply equally to SVG-as-image and inline SVG.
Organizing Assets in a Project
Typical conventions:
-
Raw SVGs in
/assets/icons/source/(human-editable). -
Optimized SVGs after SVGO or build step in
/public/icons/or inlined by the bundler. -
Naming:
icon-name.svgor BEM-style; symbol IDs match (icon-name). - Design handoff: Agree on stroke width, corner radius, and grid so icons feel cohesive.
Try It: Inline Icon in Context
Below, a tiny inline SVG uses currentColor so it inherits the button’s text color.
What Comes Next
The next reading, SVG Fundamentals and Implementation, focuses on styling strategies, optimization, caching, and tradeoffs between sprites, inline SVG, and legacy icon fonts so you can implement production-ready graphics.