Why SVGs bloat
Open any SVG exported from Illustrator, Figma, or Inkscape and you will find far more markup than the shapes actually require. Design tools are generous: they record every layer name, every editing session guid, the document creation date, the original artboard dimensions, and comments explaining their own export format. None of this is rendered by the browser.
Other common bloat sources:
- Excessive coordinate precision — design tools export up to six decimal places (
M 42.839472 18.003821). For screen graphics, one or two decimal places is imperceptible. - Redundant groups — tools wrap everything in
<g>elements for every layer, even when the layer contains a single shape with no shared transform or style. - Default attribute values — attributes like
fill-opacity="1",stroke="none", orx="0" y="0"are written explicitly even though they match the SVG default and could be removed entirely. - Hidden layers and off-canvas objects — elements outside the
viewBox, or withdisplay:none, that were never intended to appear in the final output. - Editor metadata —
<metadata>, namespaced attributes likeinkscape:labelorsodipodi:namedview, and XML processing instructions.
Before and after
The two code blocks below show the same simple icon — a magnifying glass — as exported from a typical design tool versus after cleanup. The visual result is identical; only the file weight changes.
Before — as exported
~780 bytes uncompressed
After — optimized
~210 bytes — 73% smaller
The optimized SVG renders identically. The <metadata> block, the XML declaration, the generator comment, redundant default attributes (fill-opacity="1", xml:space="preserve", the x="0" y="0" on the root), unnecessary ids on every element, and excessive decimal precision are all gone. The accessible <title> is intentionally kept.
SVGO and SVGOMG
Manually editing every exported SVG is impractical. SVGO (SVG Optimizer) is the industry-standard Node.js tool that automates this work. It applies a configurable set of plugins — each handling one category of cleanup — and can reduce file sizes by 40–70% with no visible change to the output.
Using the SVGO CLI
SVGO's default preset is aggressive but well-calibrated. For most icons and illustrations it is safe to run with no configuration. The output goes back to the same filename unless you specify -o.
SVGOMG — the browser interface
SVGOMG (svgomg.net) is a web-based GUI around SVGO. Paste or drag in an SVG, toggle individual plugins on or off with checkboxes, and see a live before/after preview with byte savings shown in real time. It is ideal for learning what each optimization does and for one-off files you do not want to install tooling for.
What to keep — caution flags
SVGO's default plugins can remove things you actually need. Before running on production files, check:
- Keep
<title>and<desc>— theremoveTitleandremoveDescplugins are enabled by default in some SVGO presets. Disable them for any SVG that will be used as a meaningful image. - Keep
idattributes you reference — if your CSS or JavaScript targets an element byid, or if another element references it via<use href="#id">, a filter, or a gradient, SVGO'scleanupIdsplugin must not remove or mangle those ids. Use thepreserveCurrentColoroption and a manual ids allowlist when needed. - Keep animation targets —
<animate>and<animateTransform>elements reference attributes by name; aggressive attribute merging can break them. - Precision vs. quality — reducing coordinate precision to 1 decimal place is usually fine for icons; for technical diagrams or detailed illustrations, 2–3 places may be necessary to avoid visible rounding artifacts.
Inline vs. external delivery
Once the SVG is optimized, you still need to decide how to include it in a page. The choice affects caching, HTTP requests, styling, and accessibility. There is no single correct answer — the right delivery method depends on the role the SVG plays.
Inline SVG
Pasting SVG markup directly into the HTML document means no extra network request. The SVG shares the page's DOM, so your page CSS can reach into it with selectors, JavaScript can query its elements, and CSS custom properties (variables) defined on the page propagate into the SVG. This is the only delivery method that allows fill: currentColor to pick up the parent's text color or that lets you animate individual shapes with CSS.
The drawbacks: inline SVG cannot be cached separately from the HTML document. If the same icon appears on ten pages, the markup is duplicated ten times in the network transfer (though gzip/brotli compress repeated text patterns very well, so the practical penalty is smaller than the raw byte count suggests). Inline SVG also increases the HTML document size, which can push the critical rendering path payload over budget on large pages.
Use inline SVG for: icons that must respond to page theme colors (dark mode, brand theming), complex illustrations that need JavaScript interaction, and one-off graphics where caching is not a concern.
External SVG via <img>
Referencing an SVG as an <img src="icon.svg"> is the simplest external method. The browser fetches the file once and caches it; subsequent pages reuse the cached copy with zero additional bytes. The SVG renders in an isolated context — page CSS cannot reach inside it, JavaScript cannot query its elements, and currentColor resolves to black regardless of the surrounding text color.
Provide a meaningful alt attribute for informative images, or alt="" for decorative ones. See tutorial 02 — Using SVG for a full comparison of all embedding methods.
Use <img> for: static illustrations and photographs-as-SVG where theming is not needed and cache efficiency matters.
SVG sprites via <use>
An SVG sprite file bundles many icons as <symbol> elements inside a single .svg file. Each symbol has its own viewBox and an id. Pages reference individual icons with <use href="sprite.svg#icon-search">, which is an external reference resolved by the browser — one HTTP request delivers all icons, and the file is cached across every page.
Unlike <img>, <use> with CSS custom properties allows limited theming (a symbol can inherit color from the host page via currentColor), though full CSS access to the symbol's internals is still restricted. See tutorial 08 — Reuse: <defs>, <use>, Symbols & Markers for the sprite authoring pattern in detail.
Compression note: SVG is text, and gzip/brotli compress text very efficiently. A 50 KB sprite sheet commonly compresses to 12–18 KB over the wire. Serve SVG files with a Content-Encoding: br or Content-Encoding: gzip header — most CDNs and web servers do this automatically.
SVG sprites vs. icon fonts
For a period in the 2010s, icon fonts (FontAwesome, Material Icons font) were the dominant way to ship icons on the web. They are now widely considered an anti-pattern. SVG sprites are the modern replacement.
Why icon fonts are discouraged
- Accessibility problems — icon font characters are typically mapped to Unicode Private Use Area codepoints. Screen readers may announce them as empty boxes, question marks, or nothing at all, depending on the OS and AT. Getting accessible icon fonts requires adding
aria-hiddento every icon element and duplicating accessible text nearby — the same overhead as a well-authored SVG, with more failure modes. - Fallback rendering failures — if the icon font fails to load (slow network, CDN outage, corporate firewall blocking external fonts), the browser falls back to a system font. The Private Use codepoints typically render as a visible "tofu" box or question mark, breaking the UI visually in a way SVG never does (a missing SVG sprite shows nothing, which is usually less disruptive).
- Styling limitations — icon fonts are single-color by nature. Multi-color icons require stacked pseudo-elements — a hack that is fragile and hard to maintain. SVG icons can have any number of colors, gradients, and fills without workarounds.
- Subpixel rendering — text rendering on some platforms applies font smoothing that makes icon fonts look blurry at small sizes. SVG renders as vectors and scales crisply at any size.
SVG sprites: the recommended pattern
A sprite file is an SVG document whose visible content area is zero-size (or hidden with CSS), containing only <symbol> definitions:
Using stroke="currentColor" inside each symbol lets the icon inherit the surrounding text color, giving you free theming. Adding a new icon is as simple as adding a new <symbol> to the sprite file — no font recompilation required.
Delivery checklist
- Run SVGO (or SVGOMG) on every exported SVG before committing it to the repository.
- Keep
<title>/<desc>in any SVG that serves as a meaningful image. - Serve sprite files from the same origin (or a CORS-enabled CDN) — cross-origin
<use href>references are blocked by the browser's security model. - Confirm your web server sends gzip or brotli encoding for
image/svg+xmlandtext/xmlcontent types. - Set a long
Cache-Controlmax-age on sprite files and use a content-hash filename (e.g.sprite.abc123.svg) to bust the cache on updates. - Avoid icon fonts in new projects; migrate existing icon font usage to SVG sprites incrementally.