Skip to content

SVG loading methods

There are several ways to display SVG images, each with its own trade-off.

The more elements per component you render, the less components and content you will be able to render before hanging or crashing the page. This is specifically true for icons which are repeated very often throughout the page, and performance impact is not realized before real issues occur.

For example, you need to display a grid of profile cards with lots of icons in buttons, action items, etc. If your markup is heavy, you’ll be able to render just a few of those cards before requiring a pagination.

Depending on the context, this may completely ruin the user experience.

However, you can avoid such a problem by simply using any alternative SVG loading method that reduces amount of SVG nodes per image/icon.

The entire SVG source code is inserted directly into the DOM for each image. This is the most popular method.

This can be achieved by importing images with ?source query parameter (or source default import option) and inserting the result directly into the DOM:

import imgSrc from "./image.svg?source";
document.getElementById("image-container")!.innerHtml = imgSrc;
  1. Pros:

    1. Simple to implement.
    2. Great customization. This is actually the only option, if you need to manipulate the content, or need more than just CSS styles.
  2. Cons:

    1. Performance will degrade with a large number (1000+) of images.

      Another loading method is always preferred when customization is not required.

The SVG is loaded via an <img> tag:

<img src="/image.svg" alt="" />

Or via background-image CSS property:

.element {
background-image: url("/image.svg");
}

This improves performance by:

  1. Reducing DOM nodes per image to one.
  2. Enabling browser to cache and reuse the same image.

This can be achieved by using ?url import or url default import option:

import imgUrl from "./image.svg?url";
const img = document.createElement("img");
img.href = imgUrl;
document.body.appendChild(img);
  1. Pros:

    1. Simple to implement.
    2. Best performance available.
  2. Cons:

    1. Lack of any customization. Works with static images only. You can’t modify external assets using JS or CSS. The only thing you can do is CSS filters (see warning above!).

mask-image property can be used to clip a filled element:

.element {
background-color: currentColor;
mask-image: url("/image.svg");
mask-size: 100%;
mask-position: center;
mask-repeat: no-repeat;
}
  1. Pros:

    1. Simple to implement.
    2. Best performance available.
    3. Fill can be customized with background and background-color properties.
  2. Cons:

    1. Limited availability. Masks are fairly new.
    2. Cannot be customized further.

This improves performance by:

  1. Reducing DOM nodes per image to one.
  2. Enabling browser to cache and reuse the same image.

SVGs are inserted into a single <svg> node (sprite sheet). Each image is wrapped with a <symbol> element and linked by a <use> tag.

<!-- Create sprite sheet -->
<svg>
<symbol id="#image1">...</symbol>
<symbol id="#image2">...</symbol>
</svg>
<!-- Use images from the sprite sheet -->
<svg>
<use href="#image1" />
</svg>
<svg>
<use href="#image2" />
</svg>
<svg>
<!-- Content of the linked images won't be duplicated with multiple <use> elements -->
<use href="#image2" />
</svg>

This improves performance by:

  1. Reducing DOM nodes per image.
  2. Enabling browser to cache and reuse the same image.

This can be achieved by importing images with ?source query parameter (or source default import option) and passing the result to the <SvgImage> or <Svg Icon> component provided by the integrations. See examples for your framework.

  1. Pros:

    1. Great performance (but worse than linking as an image or CSS mask).
    2. Images can be customized with CSS. For example, you can set custom stroke and fill colors.
  2. Cons:

    1. Requires a bit of maintenance in form of using provided integrations.
    2. Performance is worse than when linking an image.
    3. Customization is not that great when using whole SVG source code.

Either use source code or base64 in a data URI. Then set src attribute of an <img> element:

<img src="data:..." alt="" />

Or set background-image CSS property:

.element {
background-image: url("data:...");
}

This improves performance by:

  1. Reducing DOM nodes per image to one.
  2. Enabling browser to cache and reuse the same image.

This can be achieved by:

import srcDataUri from "./image.svg?source-data-uri";
import base64DataUri from "./image.svg?base64-data-uri";
const uris = [srcDataUri, base64DataUri];
for (const uri of uris) {
const img = document.createElement("img");
img.src = imgUrl;
document.body.appendChild(img);
}
  1. Pros:

    1. Great performance, although a tiny bit worse than when linking an image.
  2. Cons:

    1. Lack of any customization. Works with static images only. You can’t modify external assets using JS or CSS.
    2. Increased memory and traffic usage when linking images because of the encoding itself.
  1. If you don’t need customization, i.e. you want to display static images, use image linking or CSS masks.
  2. If you only need to customize the background, and you support only evergreen browsers, use CSS masks.
  3. If you only need custom CSS, use symbols.
  4. If you need heavy customization and interactivity, use inline SVGs.
  5. Data URIs are rarely needed. They’re implemented just for completeness sake.
  6. For icons, use CSS masks and symbols. They are suited best because of the balance between customization and performance.