icon icon indicating copy to clipboard operation
icon copied to clipboard

Auto-optimized sprites using `<symbol>` and `<use>`

Open ShayanTheNerd opened this issue 1 year ago • 3 comments
trafficstars

Astro Icon is a similar module for Astro projects that also utilizes Iconify under the hood. It automatically optimizes repeated references to the same icon on a page, using a simple approach that results in smaller HTML documents (official documentation).

In a nutshell, the first time the <Icon> component is included on a page, it defines a sprite <symbol> with a unique ID and immediately renders that symbol with the <use> element. If the same icon is referenced again, <Icon> will render only a <use> element, reducing the overall size of the HTML document by referencing the existing <symbol>.

With that said:

<Icon name="logo" />
<!-- First usage generates the following HTML -->
<svg data-icon="logo">
  <symbol id="ai:uniqueid"><!-- contents of logo.svg --></symbol>
  <use xlink:href="#ai:uniqueid"></use>
</svg>

<Icon name="logo" />
<!-- Additional usage generates the following HTML -->
<svg data-icon="logo">
  <use xlink:href="#ai:uniqueid"></use>
</svg>

It'd be nice to have this feature in Nuxt Icon module as well.

ShayanTheNerd avatar Sep 15 '24 20:09 ShayanTheNerd

Sounds like an interesting idea to avoid duplication. However, I am not sure how to handle the cases when the first icon gets unmounted while the second remains.

On the other hand, I think the CSS mode solves this problem is a much better way (which is already the the default). Wonder what's the block prevent you from using the CSS mode?

antfu avatar Sep 16 '24 09:09 antfu

Wonder what's the block prevent you from using the CSS mode?

#167 and fine-grained control over the customization of icons, especially the local ones.


I am not sure how to handle the cases when the first icon gets unmounted while the second remains.

Perhaps by inserting a hidden <svg> element right after the starting <body> tag. This <svg> would contain a <symbol> for each icon used in the current HTML document. This way, all icons are referenced by <use>, and removing one doesn't break its duplications elsewhere in the document.

<!-- First usage -->
<Icon name="logo" />
<!-- Additional usage-->
<Icon name="logo" />

<!-- Generates the following HTML -->
<body>
   <svg hidden aria-hidden="true">
      <symbol id="ai:uniqueid"><!-- contents of logo.svg --></symbol>
   </svg>

   <!-- Some other markup -->

   <!-- Note that `href` suffices since `xlink:href` has been deprecated -->
   <svg data-icon="logo">
      <use href="#ai:uniqueid"></use>
   </svg>
   <svg data-icon="logo">
      <use href="#ai:uniqueid"></use>
   </svg>
</body>

ShayanTheNerd avatar Sep 16 '24 20:09 ShayanTheNerd

that's how nuxt-sprite working

Koc avatar Sep 26 '24 17:09 Koc

Here an blogpost with PHP way of this optimization

Koc avatar Jun 30 '25 09:06 Koc

This nuxt module provides svg sprites: https://github.com/dulnan/nuxt-svg-icon-sprite/

luksak avatar Aug 25 '25 15:08 luksak

But I think people wanted this as part of the nuxt svg implementation ( as its an official module )

joaopedrodcf avatar Aug 25 '25 16:08 joaopedrodcf