SVG is one of those web technologies that looks simple until you have to decide how to actually put it on the page.
You have an illustration:
hero-illustration.svg
and two obvious options.
Load it as a normal image:
<img
src="/images/hero-illustration.svg"
alt="Illustration of a developer working at a desk"
>
or paste the SVG markup directly into the document:
<svg
viewBox="0 0 800 600"
role="img"
aria-label="Illustration of a developer working at a desk"
>
...
</svg>
Both display the same vector artwork.
But after that, they behave quite differently.
The practical difference is this:
Use inline SVG when the SVG needs to behave like part of your interface. Use
<img>when it should behave like an image asset.
That distinction covers most real projects.
Inline SVG vs <img>: Which Should You Use? #
Use inline SVG when you need to style individual paths, inherit currentColor, animate internal elements, or manipulate the illustration from JavaScript.
Use an external SVG through <img> when the artwork is mostly static, reused across pages, and should benefit from normal image loading and browser caching.
| Requirement | Inline SVG | <img src="...svg"> |
|---|---|---|
| Style internal paths from page CSS | Yes | No |
Use page currentColor inside SVG |
Yes | Not from the parent document |
| Manipulate SVG elements with JS | Yes | Not directly |
| Independent browser cache | No separate SVG request | Yes |
| Simple responsive image markup | Good | Excellent |
Native alt attribute |
No | Yes |
| ARIA can describe SVG directly | Yes | Usually use alt |
| Repeating same large artwork many times | Can duplicate markup | External file is usually cleaner |
| Component icons with dynamic color | Excellent | Limited |
| Static editorial illustration | Works | Usually preferable |
That table is the answer in compact form.
The more interesting part is understanding why.
Inline SVG Is Part of the DOM #
When you write:
<svg viewBox="0 0 24 24">
<path d="..." />
</svg>
the <svg> and <path> elements become part of the HTML document’s DOM.
CSS can reach them.
JavaScript can reach them.
Pseudo-classes and inherited properties can influence them.
For example:
<a href="/next/" class="icon-link">
<svg
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
d="..."
fill="currentColor"
/>
</svg>
Next project
</a>
Now:
.icon-link {
color: #222;
}
.icon-link:hover {
color: #ff4d30;
}
changes both the text and the icon.
No separate icon variant is required.
That is one of the strongest arguments for inline SVG in interface components.
currentColor Is Where Inline SVG Becomes Extremely Useful #
Consider a simple arrow.
Without a semantic color relationship:
<svg viewBox="0 0 24 24">
<path
d="..."
fill="#111111"
/>
</svg>
Now the color is hard-coded inside the asset.
If the surrounding button changes:
.button {
color: white;
}
the SVG does not automatically follow.
Instead:
<svg viewBox="0 0 24 24">
<path
d="..."
fill="currentColor"
/>
</svg>
lets the SVG consume the element’s current CSS color.
.button {
color: white;
}
.button:hover {
color: #d7ff43;
}
The icon follows.
This is especially useful for:
- arrows;
- chevrons;
- social icons;
- interface symbols;
- status icons;
- decorative strokes attached to text;
- monochrome logos used in multiple themes.
Why doesn’t the same thing work through <img>? #
Suppose the SVG file contains:
<path
d="..."
fill="currentColor"
/>
and you load it like this:
<img
class="icon"
src="/icons/arrow.svg"
alt=""
>
The SVG is being used as an image resource.
Its internal elements are not part of the parent page DOM, so your page stylesheet cannot simply do:
.icon path {
fill: red;
}
There is no path in the parent document for that selector to reach.
This is an important distinction.
It is not that SVG itself somehow loses CSS support.
It is that the page no longer has direct styling access to the SVG’s internal tree.
External SVG Wins at Being an Asset #
Now consider a large illustration used on:
Homepage
About
Careers
Contact
If you paste the entire SVG markup into every page, the browser receives that markup again as part of each HTML document.
If instead you use:
<img
src="/assets/brand-scene.svg"
alt=""
>
the SVG exists as its own resource.
That has an important advantage:
it can be cached independently.
Once the browser has fetched the file, subsequent pages may be able to reuse the cached resource instead of receiving the full SVG markup again inside every HTML response.
That makes <img> attractive for:
- repeated illustrations;
- logos;
- static diagrams;
- decorative artwork;
- editorial graphics;
- large SVG assets that do not need internal interactivity.
The important nuance is that inline SVG is still part of an HTML document that may itself be cached.
But it is not an independently reusable SVG resource in the same way an external file is.
For repeated assets, that distinction matters.
Repeated Icons Are Where Inline SVG Can Become Wasteful #
Imagine a table with 200 rows.
Every row contains:
<svg viewBox="0 0 24 24">
<path d="..." />
</svg>
The icon may be tiny visually.
But the complete markup is repeated 200 times.
For a simple path, this may still be trivial.
For a more complex symbol containing:
12 paths
3 groups
2 masks
1 gradient
the duplication becomes less elegant.
This is where I would start considering an SVG sprite.
SVG Sprite: A Useful Middle Ground #
A sprite lets you define SVG symbols once:
<svg
aria-hidden="true"
style="display: none"
>
<symbol
id="icon-arrow"
viewBox="0 0 24 24"
>
<path
d="..."
fill="currentColor"
/>
</symbol>
<symbol
id="icon-search"
viewBox="0 0 24 24"
>
<path
d="..."
fill="currentColor"
/>
</symbol>
</svg>
Then reuse them:
<svg
class="icon"
aria-hidden="true"
>
<use href="#icon-arrow"></use>
</svg>
Now the interface still gets convenient SVG behavior:
.icon {
width: 1em;
height: 1em;
color: currentColor;
}
without reproducing all of the path markup everywhere.
Conceptually:
INLINE EVERY TIME
<svg>
huge path
huge path
huge path
</svg>
<svg>
huge path
huge path
huge path
</svg>
SPRITE
<symbol>
huge path
huge path
huge path
</symbol>
↓
<use>
<use>
<use>
<use>
For an interface icon system, this can be a very useful compromise.
Accessibility: Inline SVG and <img> Need Different Treatment #
This is another reason the choice should be intentional.
With <img>, accessibility usually follows familiar image rules.
Meaningful image:
<img
src="/illustrations/payment-flow.svg"
alt="Diagram showing payment processing from checkout to confirmation"
>
Decorative image:
<img
src="/decorations/wave.svg"
alt=""
>
The alt attribute communicates whether the asset contributes meaningful information.
Inline SVG has no alt attribute.
Instead, meaningful inline SVG can be given an accessible name.
For example:
<svg
viewBox="0 0 800 600"
role="img"
aria-label="Diagram showing payment processing from checkout to confirmation"
>
...
</svg>
A decorative inline SVG can be removed from the accessibility tree:
<svg
viewBox="0 0 24 24"
aria-hidden="true"
>
...
</svg>
This is particularly appropriate for an icon next to visible text:
<a href="/contact/">
Contact us
<svg
viewBox="0 0 24 24"
aria-hidden="true"
>
...
</svg>
</a>
The link already says “Contact us.”
Having a screen reader announce:
Contact us, arrow icon
usually adds nothing useful.
role="img" + aria-label Is Not an Automatic Recipe #
It is tempting to turn this into a rule:
inline SVG
=
role="img" + aria-label
But that would be too simplistic.
Ask first:
Does this SVG communicate information that is not already available in nearby text?
If yes, give it an accessible name.
If no, it may be decorative and should often be hidden from assistive technology.
For complex diagrams, charts, or illustrations carrying significant information, the accessible solution may need more than a short label.
The surrounding document may need a text explanation.
Accessibility should describe the meaning of the graphic, not merely announce:
graphic.
A Practical Accessibility Comparison #
| SVG use | Recommended starting point |
| Meaningful external illustration | <img alt="Meaningful description"> |
| Decorative external SVG | <img alt=""> |
| Meaningful inline SVG | <svg role="img" aria-label="..."> |
| Decorative inline icon | <svg aria-hidden="true"> |
| Icon beside visible label | Usually hide icon from accessibility tree |
| Complex data visualization | Provide accessible name plus equivalent text/data where appropriate |
The exact implementation depends on context.
That is the part worth remembering.
What About Inline SVG for Large Illustrations? #
Inline SVG is not only for tiny icons.
There are legitimate reasons to inline a complex illustration.
For example, suppose a hero graphic contains:
character
background
floating cards
decorative lines
product screenshot
and you want to animate them separately:
.hero-illustration__card {
animation: float 4s ease-in-out infinite;
}
.hero-illustration__line {
stroke-dasharray: 120;
}
Now inline SVG becomes part of the interaction layer.
JavaScript could select:
const cards = document.querySelectorAll(
'.hero-illustration__card'
);
and animate them according to scroll, pointer movement, or product state.
An <img> cannot expose those internal elements to the surrounding page like that.
So the question becomes:
Is this graphic CONTENT?
or:
Is this graphic INTERFACE?
If it behaves like interface, inline becomes much more compelling.
Inline SVG Also Increases Your HTML #
There is a cost.
A complex exported SVG can contain enormous amounts of markup:
<g>
<g>
<path>
<path>
<path>
<clipPath>
<mask>
<linearGradient>
...
Paste several of those directly into a page and your HTML response grows quickly.
It also becomes harder to read.
This is why I would not adopt a rule like:
SVG should always be inline because it is more flexible.
Flexibility you do not use is not automatically beneficial.
If the illustration is static, this:
<img
src="/illustrations/team.svg"
alt="Our product team"
>
is wonderfully boring.
Boring is often excellent.
A Decision Tree I Actually Use #
My rough decision process is:
Do I need to style internal SVG parts
from the surrounding page?
YES
↓
Inline SVG
NO
↓
Will the same asset appear repeatedly
or across multiple pages?
YES
↓
External SVG via <img>
NO
↓
Is it a simple interface icon
repeated many times?
YES
↓
Consider SVG sprite
NO
↓
Use the simplest method
that fits the content
There are exceptions, but this catches most ordinary cases.
Brand Logos Are an Interesting Edge Case #
Logos often appear:
- in the header;
- footer;
- mobile menu;
- presentation embeds;
- partner lists;
- dark mode;
- light mode.
If the logo needs one fixed brand color, an external image is simple:
<img
src="/brand/logo.svg"
alt="AKAVA"
>
If the logo needs to inherit the surrounding theme:
.header {
color: black;
}
.footer {
color: white;
}
then an inline monochrome SVG using:
fill="currentColor"
can be much easier.
Or keep separate optimized assets:
logo-dark.svg
logo-light.svg
There is no moral victory in reducing every logo to one file.
The architecture should fit how the brand actually behaves.
CSS Masking Is Another Option for Monochrome Icons #
There is one more technique worth knowing.
For a simple monochrome external SVG, CSS masking can let you use the SVG file as a shape while controlling the visible color from CSS.
Conceptually:
.icon {
width: 24px;
height: 24px;
background: currentColor;
mask:
url('/icons/arrow.svg')
center / contain
no-repeat;
-webkit-mask:
url('/icons/arrow.svg')
center / contain
no-repeat;
}
Now the SVG remains external, but its silhouette is colored through the element’s background.
This can be useful for icon systems.
But it is not the same as having access to the SVG’s internal structure.
You cannot independently style several paths inside the same illustration this way.
Again, choose the architecture according to the job.
Performance Is Not Just File Size #
Developers sometimes reduce the entire SVG discussion to:
Which one has fewer bytes?
That is useful, but incomplete.
I would consider:
- HTML response size;
- repeated markup;
- number of network requests;
- cache reuse;
- whether the asset is above the fold;
- whether it must be manipulated;
- how many instances exist;
- SVG complexity;
- maintainability;
- accessibility implementation.
A 900-byte inline icon used once is not a performance crisis.
A 45 KB illustration duplicated inline across ten page templates deserves more thought.
A 300-byte external icon requested dozens of times may be cached efficiently, but an SVG sprite may still produce a cleaner component architecture.
Context beats slogans.
My Default Rules #
If I had to reduce everything to four practical rules:
1. Interface icon that needs dynamic color #
Use inline SVG:
<svg aria-hidden="true">
<path
fill="currentColor"
d="..."
/>
</svg>
2. Static illustration #
Use:
<img
src="/illustration.svg"
alt="..."
>
unless you have a concrete reason not to.
3. Same icon used everywhere #
Consider:
SVG sprite
rather than repeating a large inline structure.
4. Complex animated illustration #
Inline it if your CSS or JavaScript genuinely needs access to its internal layers.
Those rules get me through most projects without turning SVG delivery into a philosophy seminar.
Frequently Asked Questions #
Is inline SVG better than an <img> tag? #
Neither is universally better. Inline SVG is better when you need to style or manipulate internal SVG elements. <img> is usually simpler for static, reusable illustrations and supports normal image loading and independent resource caching.
Can CSS style an SVG loaded with <img>? #
CSS can style the <img> element itself, such as its dimensions, opacity, or filter. It cannot directly select and style internal <path> elements of the SVG from the parent document.
Does currentColor work with inline SVG? #
Yes. Inline SVG can use values such as fill="currentColor" or stroke="currentColor" and inherit the surrounding element’s CSS color.
Why doesn’t currentColor behave the same through <img>? #
An SVG loaded as an image resource has its own document context. The parent page does not have direct DOM/CSS access to the SVG’s internal paths in the same way it does with inline markup.
Is external SVG better for caching? #
An external SVG resource can be cached independently and reused across pages or repeated references. Inline SVG travels as part of the HTML document and is not a separately reusable network resource.
How do I make an inline SVG accessible? #
If the SVG is meaningful, give it an appropriate accessible name, for example with role="img" and aria-label, depending on context. If it is decorative or repeats nearby text, aria-hidden="true" may be more appropriate.
Should SVG icons have alt attributes? #
Inline <svg> elements do not support the HTML image alt attribute. SVGs loaded through <img> should use the normal alt rules for meaningful or decorative images.
Is an SVG sprite better than inline icons? #
For a frequently repeated icon set, a sprite can avoid repeating path markup while preserving a convenient SVG-based component model. For a handful of unique icons, individual inline SVGs may be simpler.
Conclusion #
The inline SVG vs <img> tag decision is easier once you stop treating both approaches as interchangeable ways to display the same file.
They represent two different relationships with the page.
An external SVG says:
This is an image asset.
Inline SVG says:
This vector structure is part
of my document and interface.
That explains most of the trade-offs.
Need currentColor, path-level CSS, JavaScript manipulation, or internal animation?
Inline it.
Need a static illustration that appears repeatedly and should behave like any other image resource?
Use <img>.
Have dozens of repeated icons?
Consider a sprite.
And whichever method you choose, make the accessibility decision at the same time.
Because the best SVG implementation is not the one with the most clever markup.
It is the one that gives the page exactly as much access to the illustration as the interface actually needs.