SVG is the ideal format for icons, illustrations, and UI graphics on the web: infinitely scalable, styleable with CSS, and accessible to screen readers. But an SVG exported from Figma, Sketch, or Illustrator is rarely production-ready. Design tools embed editor metadata, verbose identifiers, redundant group elements, and inline styles that serve no purpose in a browser context and inflate file size significantly. A well-optimized SVG can be 50–80% smaller than its exported counterpart with no visual difference.
Why SVG Optimization Matters for Performance
File size directly impacts load time, and load time directly impacts conversion rates, bounce rates, and Core Web Vitals scores. The Largest Contentful Paint (LCP) metric — one of Google's three core web vitals — measures how long it takes for the largest visible element in the viewport to render. If that element is an SVG hero illustration or a large icon set, its file size is on the critical path.
Even for smaller decorative SVGs, the cumulative impact matters. A page that loads 20 icon SVGs, each 8 KB instead of 2 KB after optimization, is transferring an extra 120 KB per page load. At 100,000 page views per day, that is 12 GB of avoidable bandwidth. SVG optimization is one of the highest-effort-to-return-ratio performance improvements available.
What Design Tools Add to SVG Files
When you export an SVG from a professional design tool, the output contains far more than the visual instructions. Here is what you typically find:
- Editor metadata and XML namespaces: Sketch adds a
sketch:typeattribute to elements. Illustrator includes anxmlns:ainamespace with Adobe-specific processing instructions. Figma embeds adata-figma-*attribute on the root SVG element. None of these are needed by a browser. - XML comments: Tools often add comments like
<!-- Generator: Adobe Illustrator 28.0 -->at the top of the file. Pure overhead. - Auto-generated IDs: Every layer and group gets a machine-generated ID like
Layer_1_00000016785orpath3847. These IDs exist for the design tool's own reference system and serve no purpose in the browser unless you specifically reference them from CSS or JS. - Redundant groups: Design tools faithfully export every layer group, including wrapper groups that contain only a single element or that apply no meaningful transform. These can be safely collapsed.
- Verbose path data: Design tools use absolute coordinates for every path node even when relative coordinates would be shorter. They also output more decimal places than visual fidelity requires.
- Inline styles vs presentation attributes: Illustrator tends to output inline
styleattributes with verbose CSS likestyle="fill:#FF0000;stroke:none;fill-rule:evenodd"when presentation attributes likefill="#FF0000"would be more compact.
SVGO: The Standard SVG Optimizer
SVGO (SVG Optimizer) is the de facto standard tool for SVG optimization. It is a Node.js library and CLI that applies a configurable pipeline of transformations to an SVG file. SVGO is used internally by most build tools that handle SVG optimization (webpack, Vite, SVGR, imagemin).
# Install SVGO globally npm install -g svgo # Optimize a single file (overwrites in place) svgo icon.svg # Optimize with output to new file svgo icon.svg -o icon.min.svg # Optimize all SVGs in a directory svgo -f ./public/icons -o ./public/icons-opt # Show what's removed without writing svgo icon.svg --dry-run
The key optimizations SVGO applies by default include:
removeComments— strips XML commentsremoveMetadata— removes the<metadata>elementcleanupIds— shortens or removes auto-generated IDsremoveUselessDefs— removes<defs>elements that contain nothing referenced in the SVGmergePaths— combines adjacent path elements with identical attributes into oneconvertTransforms— applies transform matrices directly to path coordinates, removing the transform attributeremoveEmptyAttrs— strips attributes with empty or default valuescollapseGroups— removes redundant group wrapperscleanupNumericValues— reduces decimal precision (e.g., 3.14159265 → 3.142)
Manual Optimization Techniques
Using <symbol> and <use> for Repeated Icons
If the same icon appears multiple times on a page — navigation icons, action buttons, status indicators — define the SVG path once inside a <symbol> element in a sprite sheet, then reference it with <use href="#icon-id"> at each usage site. The browser renders one definition and instances it however many times needed, with no duplicate path data in the DOM.
<!-- SVG sprite — typically hidden, placed once in the document -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-check" viewBox="0 0 24 24">
<path d="M20 6L9 17l-5-5" stroke="currentColor" fill="none"
stroke-width="2" stroke-linecap="round"/>
</symbol>
<symbol id="icon-x" viewBox="0 0 24 24">
<path d="M18 6L6 18M6 6l12 12" stroke="currentColor" fill="none"
stroke-width="2" stroke-linecap="round"/>
</symbol>
</svg>
<!-- Usage anywhere in the document -->
<svg width="24" height="24"><use href="#icon-check"/></svg>
<svg width="24" height="24"><use href="#icon-check"/></svg>
<svg width="16" height="16"><use href="#icon-x"/></svg>viewBox and Responsive Sizing
An SVG with a viewBox attribute but no explicit width and height attributes will size itself to fill its container, making it inherently responsive. Always include viewBox. Omit hard-coded width and height on SVGs that should scale with their container — control the size from CSS instead.
<!-- Non-responsive: fixed at 24x24 regardless of container -->
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">...</svg>
<!-- Responsive: scales to fill container, preserving aspect ratio -->
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">...</svg>
<!-- Size it from CSS -->
.icon { width: 1.5rem; height: 1.5rem; }Inline SVG vs img vs CSS Background
There are three ways to use SVG on the web, each with different tradeoffs:
- Inline SVG (SVG code directly in HTML): full CSS and JavaScript access, can use
currentColorfor theming, no separate HTTP request. Downsides: cannot be browser-cached independently, increases HTML document size, duplicates if used more than once. <img src="icon.svg">: cached by the browser as a separate resource, clean separation from HTML. Downsides: CSS cannot reach inside the SVG to change colors or stroke widths, JavaScript cannot manipulate it.- CSS
background-image: url(icon.svg): same caching benefit as<img>, useful for decorative elements. Completely inaccessible to assistive technologies — use only for purely decorative graphics with no semantic meaning.
The practical rule: use inline SVG for icons that need to inherit text color or respond to hover/focus states (navigation icons, button icons). Use <img> for illustrations and logos that are stable and semantically meaningful. Use CSS background for decorative patterns and textures.
SVG in React: SVGR
SVGR is the standard tool for converting SVG files to React components. It is included in Create React App and supported by Vite via the @svgr/vite plugin. SVGR runs SVGO as part of its transformation pipeline, automatically optimizing the SVG while converting it to JSX.
// vite.config.ts
import svgr from "@svgr/vite";
export default defineConfig({
plugins: [svgr()],
});
// Usage — import as a React component
import { ReactComponent as CheckIcon } from "./icons/check.svg";
function Button() {
return (
<button>
<CheckIcon width={20} height={20} aria-hidden="true" />
Save
</button>
);
}One important caveat with SVGR: when multiple SVG files are inlined in the same document, their internal IDs (used for gradients, clip paths, and masks) can collide. SVGR has a svgoConfig.cleanupIds option and also supports generating unique IDs per component instance. If your SVGs use gradients or clip paths, configure this explicitly.
Accessibility for SVG
Accessibility is not optional, and SVG has specific requirements. The correct approach depends on whether the SVG is meaningful or decorative:
- Decorative SVGs (icons that accompany text labels, background patterns): add
aria-hidden="true"so screen readers skip them entirely. - Meaningful standalone SVGs (logos, charts, icons without adjacent text): add
role="img"andaria-label="Description", or include a<title>element as the first child of the SVG element. - For complex SVGs like charts, add both a
<title>(short description) and a<desc>(longer description), then reference them witharia-labelledby.
<!-- Decorative icon (has adjacent text label) --> <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24"> <path d="..."/> </svg> <span>Save</span> <!-- Standalone meaningful icon --> <svg role="img" aria-label="Settings" viewBox="0 0 24 24"> <title>Settings</title> <path d="..."/> </svg>
Animating SVGs: Performance Considerations
Three approaches exist for SVG animation, with significantly different performance characteristics:
- CSS animations: Use
@keyframeswithtransformandopacity. These run on the browser's compositor thread and do not block the main thread. This is the correct default for simple animations. - SMIL animations (
<animate>,<animateTransform>): native SVG animation syntax. Runs off the main thread in most modern browsers but has inconsistent support and is effectively deprecated in favor of CSS and JavaScript animations. - JavaScript (GSAP, Anime.js, Web Animations API): maximum control and cross-browser consistency, but animations run on the main thread unless you carefully restrict to compositor-only properties (
transform,opacity). GSAP is the industry standard for complex SVG animations that CSS cannot express.
Common SVG Pitfalls
- Non-unique IDs: When multiple inline SVGs share an ID (e.g., both have
id="gradient1"), the browser picks the first definition for all references. Gradient colors and clip paths will appear on the wrong elements. Always scope IDs or use SVGR's unique ID generation. - Missing viewBox: An SVG without a
viewBoxcannot be resized responsively. Thewidthandheightattributes set a fixed pixel size with no scaling capability. SVGO will warn about missingviewBox. - SVG fonts: Some older design tools embed font glyphs directly in the SVG. This is inefficient and bypasses system font rendering. Convert text to paths in your design tool or use
<text>elements with a system font stack. - Deeply nested transforms: Chains of nested
transformattributes accumulate and can cause rendering inconsistencies across browsers. SVGO'sconvertTransformsplugin collapses these into a single matrix or removes them entirely when they cancel out.
Optimize your SVG files online — paste your SVG code and get an optimized version instantly, with a before/after size comparison. Open the SVG Optimizer →