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:
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.
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:
But, we managed to shave a couple of kilobytes off the page though (13.5 kB before vs 11.4kB after):
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.
Top comments (0)