SVG and UI Icons
Icons are the most frequently misimplemented element in web interfaces. They get treated as decorative afterthoughts — dropped in as image tags, loaded from external CDNs, sized with pixel values that do not scale with surrounding text, and left without any accessibility consideration. Done well, SVG icons are lightweight, scalable, styleable, and accessible. Done poorly, they add weight, create layout issues, and confuse assistive technology users. This guide covers the practical decisions involved in shipping production icon systems: delivery method, sizing, accessibility markup, and performance. It is written for developers and designers who need icons that work reliably across browsers, devices, and interaction contexts.
Our icon implementations span hundreds of production interfaces over the past decade — from compact mobile navigations where every pixel matters to editorial layouts where icons serve as wayfinding cues rather than primary interactive elements. The patterns here reflect what survives contact with real usage across that range.
Why SVG Over Icon Fonts
Icon fonts were the standard approach for most of the 2010s, and they still appear in legacy codebases. The arguments against them are now well-established: they are a text rendering hack (icons are not text), they fail unpredictably when font loading fails, they produce blurry rendering on some subpixel configurations, and they are invisible to users who override fonts for accessibility reasons.
SVG resolves all of these issues. Each icon is a first-class graphic element with explicit geometry, declared dimensions, and the ability to carry accessibility attributes. The MDN Web Docs SVG reference provides comprehensive documentation on SVG elements, attributes, and browser support — it is the most reliable technical reference available.
Delivery Methods
Inline SVG
The SVG markup is embedded directly in the HTML. This is our default approach for icons that need to respond to CSS state changes (hover, focus, active) or that appear in interactive components.
Advantages: no additional HTTP requests, full CSS styling control, can be animated with CSS or JavaScript, renders immediately.
Disadvantages: increases HTML document size, not cached independently, can clutter templates.
SVG Sprite Sheet
Multiple icons defined in a single SVG file using <symbol> elements, referenced via <use> with fragment identifiers. This is our approach for icon sets used across multiple pages.
Advantages: single cacheable file for all icons, clean template markup, DRY principle applied to icon definitions.
Disadvantages: initial implementation complexity, requires build tooling to generate the sprite, cross-origin restrictions on external sprite files in some browsers.
External SVG Files
Each icon is a separate .svg file loaded via <img> tag or CSS background-image. This is appropriate only when icons are purely decorative and do not need CSS styling.
Advantages: independently cacheable, simple implementation.
Disadvantages: no CSS fill/stroke control, additional HTTP requests, cannot carry accessible names.
Sizing System
Icons should scale with their surrounding text context. The most reliable approach: size icons in em units relative to their parent font size.
A 1em icon is the same height as the parent text's line box. For interface icons alongside text (buttons, navigation items, list markers), 1em or 1.25em produces natural alignment. For standalone decorative icons, size in rem to maintain consistency regardless of text context.
The critical detail: SVG icons need a viewBox attribute that matches their design grid. An icon designed on a 24×24 grid should have viewBox="0 0 24 24". The actual rendered size is then controlled by CSS width and height, and the icon scales perfectly because SVG is vector-based.
Accessibility Patterns
Decorative Icons
Icons that duplicate adjacent text (a magnifying glass next to the word "Search") should be hidden from assistive technology:
<svg aria-hidden="true" focusable="false">...</svg>
The focusable="false" is specifically for Internet Explorer and older Edge, which made SVG elements focusable by default. Include it as a defensive measure.
Informative Icons
Icons that convey meaning not available in surrounding text need an accessible name:
<svg role="img" aria-label="Settings">...</svg>
Or using a <title> element inside the SVG:
<svg role="img" aria-labelledby="icon-title">
<title id="icon-title">Settings</title>
...
</svg>
Interactive Icons
Icon-only buttons must have an accessible name on the button, not on the icon:
<button aria-label="Close menu">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
This pattern keeps the accessible name on the interactive element where assistive technology expects to find it.
Checklist
- [ ] All icons use SVG (no icon fonts in new code)
- [ ] Every SVG has a
viewBoxattribute matching its design grid - [ ] Icon sizes use
emorremunits (no pixel values) - [ ] Decorative icons have
aria-hidden="true"andfocusable="false" - [ ] Informative icons have
role="img"and an accessible name - [ ] Interactive icon buttons have the accessible name on the
<button>, not the SVG - [ ] SVG sprite sheet is used for icon sets appearing on multiple pages
- [ ] Icon fill colors use
currentColorfor automatic text color inheritance - [ ] Icons are tested at 200% browser zoom without overflow or clipping
- [ ] No icons are loaded from external CDNs
Field-Tested Observations
currentColor is the most important SVG trick. Setting fill="currentColor" on SVG paths makes the icon inherit its parent element's text color. This means icons automatically respond to hover states, focus styles, dark mode changes, and any other color context without additional CSS. We use this on every project.
Sprite sheet caching is overrated for small icon sets. If your site uses fewer than 10 icons, inlining them directly produces less total weight than the sprite sheet overhead (the <symbol> definitions, the <use> references, the extra HTTP request for the sprite file). Sprite sheets pay off at scale — 20+ icons used across multiple pages.
Icon alignment with text is harder than it looks. Even with em sizing, icons and text often appear vertically misaligned because the icon's visual center does not match the text's baseline. The fix is usually a small vertical-align adjustment or a slight transform: translateY() — values between -0.1em and 0.15em cover most cases.
Animating SVG icons is tempting and usually wrong. Subtle animations (a gentle rotation on a loading icon, a check mark drawing itself) add polish. Complex animations (bouncing notifications, pulsing hearts, spinning logos) add distraction. The threshold is lower than most designers think.
Common Pitfalls
-
Using
<img>for icons that need color changes. An SVG loaded via<img>is a black box — you cannot style its internals with CSS. Use inline SVG or sprites for any icon that needs to respond to state changes. -
Missing
viewBoxattribute. WithoutviewBox, SVGs render at their intrinsic size and do not scale responsively. Always include it. -
Hardcoded fill colors inside SVG markup. If your SVG has
fill="#333333"on its paths,currentColorinheritance will not work. Strip hardcoded colors during your build process or when adding icons to your system. -
Loading icon libraries you barely use. A full icon library is often 200+ icons when you need 8. Import only what you use, or better yet, maintain your own curated set.
FAQ
How many icons are too many for inline SVG?
There is no hard threshold, but if you are inlining the same icon on 50+ pages, a sprite sheet will reduce total HTML weight. For pages with fewer than 10 unique icons, inline SVG is fine.
Should I use SVG or CSS for simple shapes?
For simple geometric shapes (circles, squares, arrows made of borders), CSS can be lighter. For anything more complex — or anything that needs to be consistent across the codebase — use SVG. The maintenance cost of CSS shape tricks exceeds their weight savings.
What about SVG accessibility in emails?
Email client SVG support is inconsistent. For email, fall back to PNG with appropriate alt text. SVG icon systems are for web interfaces, not email templates.
Can I animate SVG icons with CSS transitions?
Yes. SVG elements respond to CSS transition and animation properties. You can transition fill, stroke, opacity, and transform on SVG elements just like HTML elements. Use stroke-dasharray and stroke-dashoffset for line-drawing animations.
How do I handle icons in right-to-left layouts?
Directional icons (arrows, chevrons, text alignment indicators) need to be flipped in RTL contexts. Use transform: scaleX(-1) triggered by a [dir="rtl"] selector. Non-directional icons (close, search, settings) should not be flipped.
What is the performance impact of inline SVG?
For typical icon usage (5–15 icons per page, each under 1KB), the impact is negligible — well under 15KB total added to the HTML document. This is almost always less than a single icon font file or an external sprite sheet request.
Related Reading
- Semantic HTML Layouts — how icons fit into document structure
- Cache and Performance — asset loading strategies including icon delivery
- Typography and Readability — sizing icons relative to text