DEV Community

Cover image for Same SVG, Different Runtime: Why "<img>", CSS, Inline SVG, and `<object>` Are Not Equivalent
Svg/icons
Svg/icons

Posted on

Same SVG, Different Runtime: Why "<img>", CSS, Inline SVG, and `<object>` Are Not Equivalent

An SVG file does not have one fixed behavior.

The exact same asset can become:

  • part of the page DOM,
  • an isolated image resource,
  • a CSS background,
  • a mask,
  • a separate document,
  • or a referenced symbol.

The bytes may be identical.

The runtime is not.

That distinction matters because the way an SVG enters a page affects what you can do with it: styling, scripting, interaction, accessibility, caching, external references, and even how much of the SVG remains relevant.

So instead of asking:

How do I embed an SVG?

a more useful question is:

Which SVG embedding mode preserves the capabilities I actually need?

Let's compare them.


One SVG, several runtimes

Imagine we start with a single SVG file:

<svg
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 24 24"
  width="24"
  height="24"
>
  <title>Status icon</title>

  <circle
    cx="12"
    cy="12"
    r="9"
    fill="currentColor"
  />

  <path
    d="M8 12.5l2.5 2.5L16 9.5"
    fill="none"
    stroke="white"
    stroke-width="2"
  />
</svg>
Enter fullscreen mode Exit fullscreen mode

Now suppose we want to use this same icon throughout a web application.

There are several ways to do it.


1. Inline SVG: the SVG joins the page

<svg viewBox="0 0 24 24" aria-hidden="true">
  <circle cx="12" cy="12" r="9" fill="currentColor" />
  <path
    d="M8 12.5l2.5 2.5L16 9.5"
    fill="none"
    stroke="white"
    stroke-width="2"
  />
</svg>
Enter fullscreen mode Exit fullscreen mode

This version becomes part of the HTML document.

That changes almost everything.

You can style it directly:

button svg {
  color: rebeccapurple;
}
Enter fullscreen mode Exit fullscreen mode

You can target individual SVG elements:

button svg path {
  stroke-width: 2.5;
}
Enter fullscreen mode Exit fullscreen mode

JavaScript can also access the SVG elements through the DOM.

const icon = document.querySelector("button svg");
Enter fullscreen mode Exit fullscreen mode

For an icon system, inline SVG offers the highest degree of control.

It is especially useful when:

  • the icon color follows surrounding text,
  • the icon changes state,
  • internal SVG elements need styling,
  • accessibility information must be controlled precisely,
  • or the SVG participates in interaction.

The trade-off is that every inline instance becomes markup in the page.

If you render hundreds of icons, that can mean a larger DOM than using external image resources.


2. <img>: the SVG becomes an image

The same file can instead be loaded like this:

<img src="/icons/status.svg" alt="Available">
Enter fullscreen mode Exit fullscreen mode

The browser still renders SVG.

But from the surrounding HTML document's point of view, it is now an image resource.

That means the SVG's internal elements do not join the parent DOM.

You cannot do this:

img circle {
  fill: red;
}
Enter fullscreen mode Exit fullscreen mode

The page cannot reach inside the SVG that way.

This is a major conceptual difference.

With inline SVG, the page owns the SVG structure.

With <img>, the page owns an image element whose source happens to be SVG.

That isolation can actually be useful.

External SVG files can be cached by the browser, and the markup of the icon does not have to be repeated directly inside the HTML.

For static icons, logos, or illustrations, this can be exactly what you want.

But if you need fine-grained styling from the parent page, <img> is much less flexible.


3. CSS background-image: the SVG becomes presentation

Another option is:

.status-icon {
  width: 24px;
  height: 24px;

  background-image: url("/icons/status.svg");
  background-repeat: no-repeat;
  background-size: contain;
}
Enter fullscreen mode Exit fullscreen mode

Now the SVG is no longer represented by an HTML image element at all.

It is part of the CSS rendering of another element.

That changes the semantic role.

A background image is normally presentation rather than content.

For decorative graphics, that is often appropriate.

For meaningful icons, it can be problematic if the visual itself is expected to communicate information.

CSS backgrounds also do not give the parent document access to the SVG's internal DOM.

From the page's perspective, the SVG behaves like an external graphic resource.

This makes backgrounds useful for:

  • decorative assets,
  • visual textures,
  • repeating patterns,
  • non-semantic UI decoration,
  • and situations where the surrounding element already carries the meaning.

But they are usually not the best choice when the SVG itself needs semantic or interactive behavior.


4. CSS mask-image: only the shape survives

SVG becomes even more interesting when used as a mask.

For example:

.status-icon {
  width: 24px;
  height: 24px;

  background-color: currentColor;

  mask-image: url("/icons/status.svg");
  mask-repeat: no-repeat;
  mask-size: contain;
  mask-position: center;
}
Enter fullscreen mode Exit fullscreen mode

Here the SVG is not being rendered in the same way as a normal image.

Its geometry is being used to determine where the element should be visible.

Conceptually, this is very different.

The SVG supplies the shape.

The CSS element supplies the color.

That is why masks work particularly well for monochrome icon systems.

For example:

.icon {
  color: #2563eb;
}

.icon:hover {
  color: #1d4ed8;
}
Enter fullscreen mode Exit fullscreen mode

The icon can follow currentColor even though the SVG remains an external asset.

But much of the original SVG's visual information becomes irrelevant.

Individual fills, complex colors, and some internal styling are no longer what define the final result.

For masks, the SVG is primarily geometry.

This makes mask-based icon systems powerful, but only when the asset is designed for that purpose.


5. <object>: the SVG becomes its own document

Now consider:

<object
  data="/icons/status.svg"
  type="image/svg+xml"
></object>
Enter fullscreen mode Exit fullscreen mode

This looks superficially similar to <img>.

It is not.

An SVG loaded through <object> is treated as a separate document.

That means it has its own document context rather than simply behaving like an image resource.

This opens possibilities that do not exist in the normal image context.

For example, the SVG document can contain its own styles, links, interaction, and scripting where allowed by the relevant browser and security context.

But this also introduces another boundary.

The SVG is no longer part of the parent DOM in the same sense as inline SVG.

So <object> provides richer document behavior, but at the cost of increased separation.

For ordinary icons, that is usually unnecessary.

For complex or interactive SVG documents, however, the distinction can matter.


6. External <use>: reuse has its own rules

SVG also provides a native reuse mechanism:

<svg class="icon" aria-hidden="true">
  <use href="/icons/sprite.svg#status"></use>
</svg>
Enter fullscreen mode Exit fullscreen mode

A sprite file might contain:

<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="status" viewBox="0 0 24 24">
    <circle cx="12" cy="12" r="9" fill="currentColor" />
    <path
      d="M8 12.5l2.5 2.5L16 9.5"
      fill="none"
      stroke="white"
      stroke-width="2"
    />
  </symbol>
</svg>
Enter fullscreen mode Exit fullscreen mode

This looks like a compromise between inline SVG and external assets.

You get a lightweight <svg> element in the document while the underlying geometry can live elsewhere.

But <use> is not simply equivalent to copying and pasting the source SVG into the DOM.

Referenced SVG content has its own behavior and styling rules.

That is why sprite systems should be tested as their own integration model rather than assumed to behave exactly like fully inline SVG.


Same file, different capability set

The important point is not that one embedding method is universally better.

The important point is that each one creates a different execution environment.

Here is a practical summary.

Capability Inline <svg> <img> CSS background CSS mask <object> External <use>
Part of the parent DOM Yes No No No No, separate document Partially through instance model
Parent CSS control High Low Low Controls host/mask Separate document Moderate
Fine-grained element styling Yes No No No Inside SVG document Limited compared with inline
currentColor workflow Excellent Context-dependent Limited Excellent for monochrome shapes Inside document Often useful
Parent JavaScript DOM access Direct No No No Separate document boundary Limited
Browser caching as external asset No Yes Yes Yes Yes Yes
Good for semantic icons Excellent Good with alt Usually no Depends on host element Possible but heavy Good with proper host markup
Good for decorative graphics Yes Yes Excellent Excellent Usually excessive Yes
Good for interactive SVG Excellent No No No Yes Limited
Good for monochrome icon systems Excellent Limited Possible Excellent Possible Excellent

The table is more useful than asking which method is "best."

There is no single best SVG runtime.

There is only the runtime that matches the capability you need.


currentColor exposes the difference clearly

One of the easiest ways to see these differences is currentColor.

Suppose an icon contains:

<path fill="currentColor" d="..." />
Enter fullscreen mode Exit fullscreen mode

With inline SVG:

<button class="danger">
  <svg>...</svg>
  Delete
</button>
Enter fullscreen mode Exit fullscreen mode
.danger {
  color: crimson;
}
Enter fullscreen mode Exit fullscreen mode

the SVG naturally participates in the surrounding document's color system.

This is one reason inline SVG works so well inside component libraries.

But an external SVG used through <img> does not simply inherit the surrounding HTML element's color property in the same way.

The resource has crossed a document boundary.

Using a mask changes the model again.

Instead of asking the SVG to inherit the color, CSS paints the host element and uses the SVG only as the visible shape.

Same icon.

Three completely different styling models.


Accessibility also depends on the runtime

Embedding mode changes how accessibility should be handled.

For <img>, the HTML element carries the alternative text:

<img src="/icons/warning.svg" alt="Warning">
Enter fullscreen mode Exit fullscreen mode

For inline SVG, you can control SVG semantics directly.

For example:

<svg
  role="img"
  aria-labelledby="warning-title"
  viewBox="0 0 24 24"
>
  <title id="warning-title">Warning</title>
  ...
</svg>
Enter fullscreen mode Exit fullscreen mode

For decorative icons, you may instead hide the graphic from assistive technologies:

<svg aria-hidden="true">
  ...
</svg>
Enter fullscreen mode Exit fullscreen mode

CSS backgrounds are different again.

They generally should not be relied upon to communicate essential meaning because they belong to presentation rather than document content.

So accessibility is not a property of the SVG file alone.

It is a property of the combination:

SVG + embedding mode + surrounding markup.


Caching and DOM control pull in opposite directions

Another practical difference is caching.

An external file:

<img src="/icons/status.svg" alt="">
Enter fullscreen mode Exit fullscreen mode

can be cached independently by the browser.

The same applies to CSS resources and external SVG sprites.

Fully inline SVG cannot use that exact resource-cache model because the markup is already embedded into the HTML or generated directly by the application.

On the other hand, inline SVG gives you immediate DOM access and styling flexibility.

This creates a common trade-off:

external resource → better reuse and caching

versus

inline markup → better control

Modern applications often use both depending on the role of the asset.


Choose the runtime from the job

A useful rule is to start with what the graphic needs to do.

UI icons

Inline SVG or SVG symbols are often the strongest choices when icons must:

  • follow currentColor,
  • change with component state,
  • participate in accessibility semantics,
  • or be styled by a design system.

CSS masks are also excellent for monochrome icon systems.

Logos

If the logo is essentially a static image, <img> is often sufficient.

You usually do not need DOM access to every path in a company logo.

Decorative graphics

CSS backgrounds are appropriate when the graphic is purely visual and does not communicate information by itself.

Interactive SVG

If individual SVG elements react to user input, inline SVG provides the most direct integration with the surrounding page.

A dedicated SVG document loaded through <object> may also make sense for larger self-contained interactive graphics.

Large illustrations

For complex static illustrations, an external <img> is often simpler and keeps the page DOM smaller.


The file is only half of the decision

SVG is often discussed as though the file itself determines its capabilities.

It does not.

The browser also needs to know how that file participates in the page.

The same SVG can be:

SVG source
   │
   ├── inline <svg> ──────► document DOM
   │
   ├── <img> ─────────────► image resource
   │
   ├── CSS background ────► presentation
   │
   ├── CSS mask ──────────► geometry / silhouette
   │
   ├── <object> ──────────► separate document
   │
   └── <use> ─────────────► referenced SVG instance
Enter fullscreen mode Exit fullscreen mode

Those are not merely six syntaxes for displaying the same thing.

They are six different contracts between the SVG and the browser.

And that is why changing the embedding method can suddenly change styling, interaction, accessibility, scripting, references, or caching even though the SVG file itself has not changed at all.


Final rule

When choosing how to integrate an SVG, don't start with:

Which syntax is shortest?

Start with:

Which capabilities does this graphic need once it is inside the page?

Then choose the embedding mode that preserves them.

Because with SVG:

same file does not necessarily mean same runtime.


Further reading

Top comments (0)