How I optimized SVG icons on my website

How I optimized SVG icons on my website

So I was looking at my website the other day, at the bookmarks page in particular. What I realized was that every bookmark had an embedded SVG icon next to it:


Places where embedded SVG elements are located

That little arrow telling you that the link will open in a new tab actually looks like this:

<svg
id=“svg-icon-external-link”
viewBox=“0 0 24 24”
fill=“currentColor”
>
<path d=“M8 7C8 6.44772 8.44772 6 9 6L17 6C17.5523 6 18 6.44772 18 7V15C18 15.5523 17.5523 16 17 16C16.4477 16 16 15.5523 16 15V9.41421L7.70711 17.7071C7.31658 18.0976 6.68342 18.0976 6.29289 17.7071C5.90237 17.3166 5.90237 16.6834 6.29289 16.2929L14.5858 8L9 8C8.44772 8 8 7.55228 8 7Z”></path>
</svg>

And since there are 20 bookmarks per page, this thing is duplicated all over the page. So inefficient! This made me wonder if there was a way to have only one definition of the icon on the page and just reference it from all those 20 places. And as it turned out, there indeed was a way!

Enter <use> and <symbol> elements

As MDN says, the <use> element takes nodes from within the SVG document and duplicates them somewhere else. The effect is the same as if the nodes were deeply cloned into a non-exposed DOM and then pasted where the <use> element is.

It can be used in combination with symbol and defs elements that define the “template” to reuse an SVG. In other words – the <symbol> is an “object” and the <use> works as a “pointer” to that object.


SVG <symbol> referenced by <use> pointers

The implementation

So, I created an <svg> at the beginning of the <body> with all the icons that I have inside as <symbol> elements within a <defs>:

<!– At the beginning of the <body> element –>
<svg width=“0” height=“0”>
<defs>
<!– The icon template definition –>
<symbol
id=“svg-icon-external-link”
viewBox=“0 0 24 24”
fill=“currentColor”
>
<path d=“M8 7C8 6.44772 8.44772 6 9 6L17 6C17.5523 6 18 6.44772 18 7V15C18 15.5523 17.5523 16 17 16C16.4477 16 16 15.5523 16 15V9.41421L7.70711 17.7071C7.31658 18.0976 6.68342 18.0976 6.29289 17.7071C5.90237 17.3166 5.90237 16.6834 6.29289 16.2929L14.5858 8L9 8C8.44772 8 8 7.55228 8 7Z”></path>
</symbol>

<!– … Other icons … –>
</defs>
</svg>

Every icon must have a unique id because we are going to pass it to our <use> elements as a href attribute to point to the definitions. Also notice the width=”0″ height=”0″ attributes – if they are not specified, the icon definitions will take actual space in the document, which might affect the layout of your page.

I also replaced every embedded <path> with a <use> pointing to the id of the according <symbol> (with a # at the beginning of the id):

<svg height=“18” width=“18”>
<!– Instead of embedding a <path> element –>
<use href=“#svg-icon-external-link” />
</svg>

The result

The page still looks the same:


Icons after the optimization

But, we managed to shave a couple of kilobytes off the page though (13.5 kB before vs 11.4kB after):


Chrome web inspector showing the difference between page sizes

Considerations

Of course, such optimization will most likely be negligible in this case, but it is a great technique to have in your arsenal for situations when you have an SVG-heavy page (like Twitter, for example, with all their “like” and “repost” buttons).

Another great thing about this technique is that it promotes the DRY principle – you have only one thing and reuse it if necessary. If the icon needs to be changed, you only have to edit a single place in the codebase.

My original blog post

Leave a Reply

Your email address will not be published. Required fields are marked *