Inline SVG and icon markup
viewBox coordinates, currentColor, symbol sprites, accessible names and hiding decorative graphics.
Coordinates and viewBox
Inline SVG is markup in your document: it inherits CSS, scales without blurring, and needs no extra request. The viewBox defines the internal coordinate system, while width and height define the rendered size.
<svg viewBox="0 0 24 24" width="24" height="24"
fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round">
<path d="M4 12h16M12 4v16"/>
</svg>viewBox="0 0 24 24" means the drawing lives on a 24 by 24 grid starting at the origin. Changing only width and height scales everything inside proportionally, so the same icon can render at 16px in a table and 48px in a hero.
- Omit
viewBoxand the drawing clips instead of scaling — the single most common inline SVG bug. preserveAspectRatiodefaults to centring the drawing, which is usually what you want.- Stroke art needs
fill="none"; filled art needs no stroke. Mixing the two is what makes icons look muddy. - Set
vector-effect="non-scaling-stroke"when a stroked icon is scaled and the line weight should stay constant.
currentColor and sprite symbols
currentColor makes a shape take the computed color of its context, which means one icon file can serve a dark toolbar, a red danger button and a link hover with no extra assets.
<svg style="display:none" aria-hidden="true">
<symbol id="icon-search" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="7"/>
<path d="M16 16l4 4"/>
</symbol>
</svg>
<button type="button" class="toolbar-btn">
<svg width="20" height="20"><use href="#icon-search"></use></svg>
Search
</button>- Define each icon once as a
<symbol>and reference it with<use href="#id">to keep markup short. - Ship the sprite container with
display:noneso the definitions never take up space. - Styling through
<use>is limited: inherited properties such ascolor,fillandstrokereach the shadow content, but a class selector targeting an inner path does not. - An external sprite file must be same-origin and cannot be used to inherit
currentColoracross origins.
Naming and hiding icons
An inline SVG is a graphic in the accessibility tree. Whether it should be announced depends entirely on whether the icon carries meaning that is not already written next to it.
| Situation | Correct markup |
|---|---|
| Icon conveys meaning alone | role="img" plus aria-label="Settings" on the SVG |
| Icon sits beside its own text label | aria-hidden="true" on the SVG |
| Icon is the only content of a button | aria-label on the button, SVG hidden |
| Logo wrapped in a link | Text or aria-label on the link naming the destination |
| Purely decorative flourish | aria-hidden="true", no label |
<button type="button" aria-label="Close">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
<path d="M6 6l12 12M18 6L6 18"/>
</svg>
</button>
<svg viewBox="0 0 24 24" role="img" aria-label="Warning">
<path d="M12 3l9 16H3z"/>
</svg><img> with appropriate alt instead when the graphic is complex, photographic, or not part of the surrounding text.FAQ
Why does fill on my inline SVG have no effect?
fill presentation attribute, which beats an inherited value. Set fill on the shape, or remove the attribute so the inherited colour applies.Inline SVG or an img tag pointing at an SVG file?
currentColor, be styled by CSS or be animated. An <img> when you want the file cached separately and referenced from many pages with a stable alt.Related
Responsive and performant images in practice Interactive elements without JavaScript
Last refreshed 2026-09-18.