DEV Community

Rails Designer
Rails Designer

Posted on Originally published at railsdesigner.com on

SVG sprites: improve performance (and keep configurability)

A table with 200 rows and 5 action icons per row. That’s 1,000 inline SVGs dropped into your HTML. When does that start to impact your performance?

By default, Rails Icons renders each icon as a full <svg> element. Fine for a handful of icons. But at scale, it adds up.

I built a simple benchmark to measure exactly how much (feel free to fork and improve ❤️). Two pages, identical layout, 1,000 icons each. One uses inline SVGs you use and love. The other uses an SVG sprite you will surely start to love after reading this. 😬

The benchmark is on GitHub.

How SVG sprites work

A SVG sprite is a single file (but can also be embedded) with multiple icon definitions wrapped in <symbol> tags:

<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="user" viewBox="0 0 24 24">
    <!-- path -->
  </symbol>
  <symbol id="pencil" viewBox="0 0 24 24">
    <!-- path -->
  </symbol>
</svg>

Enter fullscreen mode Exit fullscreen mode

To render an icon, reference it with <use>:

<svg class="icon"><use href="/sprite.svg#user"/></svg>

Enter fullscreen mode Exit fullscreen mode

The browser downloads the sprite file once and caches it. Every <use> is a lightweight DOM reference, not a full SVG subtree. Compare that to inline SVGs where every single icon is a complete <svg> element with all its paths. 1,000 icons means 1,000 unique SVG subtrees parsed, styled and laid out by the browser.

Why not font icons or image tags?

Before SVGs became the standard, font icons were the go-to (if you been around for some time, you surely have used them; I thought they were really cool!). They have problems: limited to one color (unless you stack multiple fonts), inconsistent rendering across browsers and operating systems and poor accessibility. And you’re loading an entire font file for a handful of icons.

Image tags (<img src="icon.svg">) solve the accessibility issue but you lose all styling control. You can’t change the color, stroke width or size via CSS. Every variant needs a separate file. Ouch!

SVG sprites give you the best of both. The <use>-element inherits CSS from the parent <svg>, so you can control color, size and stroke width the same way you do with inline SVGs.

Fully configurable, single HTTP request, accessible by default.

The benchmark

Two pages, identical layout, 1,000 icons each:

  • 200 users in a table, 5 icons per row
  • Same ERB template, same CSS, same layout
  • Only difference: one page uses icon, the other uses sprite_icon (both helper methods from Rails Icons)

Inline:

<%= icon "user" %>
<%= icon "pencil" %>
<%= icon "arrow-path" %>
<%= icon "lock-closed" %>
<%= icon "trash" %>

Enter fullscreen mode Exit fullscreen mode

Sprite:

<%= sprite_icon "user" %>
<%= sprite_icon "pencil" %>
<%= sprite_icon "arrow-path" %>
<%= sprite_icon "lock-closed" %>
<%= sprite_icon "trash" %>

Enter fullscreen mode Exit fullscreen mode

The numbers

Metric Inline SVGs SVG Sprite Difference
Single icon markup ~1.7 KB ~170 bytes 90% smaller
Total icon HTML (1,000x) ~1.7 MB ~170 KB 90% smaller
Rendered page size ~1.8 MB ~250 KB 86% smaller
DOM nodes ~13,000 ~7,000 46% fewer
DOM loaded ~320ms ~210ms 34% faster

The sprite page loads faster, transfers less data and creates a simpler DOM tree.

Using sprites with Rails Icons

Rails Icons 1.9+ ships with built-in sprite support. Configure which icons to include in your initializer:

# config/initializers/rails_icons.rb
RailsIcons.configure do |config|
  config.default_library = "heroicons"

  config.sprite = {
    heroicons: {
      outline: %w[user pencil arrow-path lock-closed trash]
    }
  }
end

Enter fullscreen mode Exit fullscreen mode

Then use sprite_icon in your views:

<%= sprite_icon "user" %>
<%= sprite_icon "pencil" %>

Enter fullscreen mode Exit fullscreen mode

That’s it. The sprite file is served at /rails_icons/sprite.svg. This means you can:

  • Cache it ; it changes only when you add or remove icons
  • Put it behind a CDN ; it’s a static asset

When to reach for sprites

Inline SVGs are fine when you have a couple dozen of icons per page. Landing pages, simple forms, blog posts. The extra bytes don’t matter.

Sprites are a good choice when icons multiply. Like with data tables, kanban boards and activity feeds.

The trade-off is one extra HTTP request for the sprite file. On an icon-heavy page, that request pays for itself many times over. 💪


SVG sprites are available in Rails Icons 1.9. Add them to your next icon-heavy view and see the difference.

Top comments (0)