What is the best method for efficiently loading SVG icons on an HTML page without redundancy? / Is utilizing <use href> recommended?

My struggle with implementing icons in Angular

While working on a new Angular project, I've encountered challenges with my current SVG-icon implementation method from a previous project (@ngneat/svg-icon). The process involves organizing SVG files in a folder, registering them in Typescript, and compiling them into (iconName).ts files using a script.

A simpler approach

In my current project, I came across a more straightforward SVG implementation while exploring Bootstrap documentation:

Source: https://getbootstrap.com/docs/5.0/components/alerts/

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="check-circle-fill" fill="currentColor" viewBox="0 0 16 16">
    <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
  </symbol>
  <symbol id="info-fill" fill="currentColor" viewBox="0 0 16 16">
    ...
</svg>
...
</pre>
<p>This method involves adding all SVG icons as symbols in a hidden element, assigning appropriate IDs to the icons, and referencing them using xlink:href anywhere on the page.</p>
<h3>Concern about deprecation</h3>
<p>Although MDN mentions that xlink:href is deprecated (<a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href" rel="nofollow noreferrer">Source</a>), many sources suggest that it won't be removed due to widespread usage, like in Bootstrap. So, I'm considering sticking with it.</p>
<h3>An alternative without deprecation</h3>
<p>The MDN page for SVG <use> (<a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use" rel="nofollow noreferrer">Source</a>) offers an example using only href instead of xlink:href. Testing this on my site showed promising results.</p>
<pre><code><svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
  <circle id="myCircle" cx="5" cy="5" r="4" stroke="blue"/>
  <use href="#myCircle" x="10" fill="blue"/>
  ...
</svg>

The Dilemma

In essence, the question boils down to "what is the best way to implement icons?" Here are some queries to consider:

  • Should I continue using xlink:href based on Bootstrap's usage?
  • Is <use href> a viable replacement or designed for different purposes?
  • Does hiding paths impact performance or page load, as all icons would be included in the HTML even if not displayed?

Answer №1

a cutting-edge <svg-icon> W3C standard Web Component (JSWC) has the ability to generate SVG on the client-side

If you specify the Web Component (along with icon path information) within a <script> in the <head> section of your HTML document, there is no need for additional downloads, and icons will be instantly displayed when utilized.

All necessary HTML code to showcase 3 icons:

<svg-icon is="menu"></svg-icon>
<svg-icon is="settings"></svg-icon>
<svg-icon is="renew" rotate=45 fill=blue stroke=white></svg-icon>

The complete script:

<script>
((t,e={path:(t,e="")=>`<path d='${t}' ${e}/>`},r={v1:"",v2:"",v3:"",is:"",img:1,box:9,rect:"<rect width='100%' height='100%' fill='{tile}' {border}/>"
,border:"",filter:"",tile:"none",fill:"none",width:1,scale:1,opacity:1,rotate:0,stroke:"#000",xy:0,w:0,h:0,top:"",api:[t,e]})=>{
customElements.define("svg-icon",class extends HTMLElement{static get observedAttributes(){return Object.keys(r)}attributeChangedCallback(){this.svg()}svg(i=this,s=i.A||Object.keys(i.A={...r}).map((t=>Object.defineProperty(i,t,{set:e=>i.setAttribute(t,e),get:()=>i.getAttribute(t)||getComputedStyle(i).getPropertyValue("--svg-icon-"+t).replace(/"/g,"").trim()||i.A[t]},e[t]=e=>(i.A[t]=e,"")))),l,a=(t[i.is]||"").split`;`.map((t=>([s,l]=t.trim().split`:`,e[s]?e[s].apply(i,l.split`,`):t))).join``,o=i.box/2,
c=`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${i.w||i.box} ${i.h||i.box}'>${i.rect}<g stroke-width='{width}' stroke='{stroke}' fill='{fill}' opacity='{opacity}' filter='{filter}' transform='translate({xy}) matrix({scale} 0 0 {scale} ${o-o*i.scale} ${o-o*i.scale}) rotate({rotate} ${o} ${o})'>${a}</g>${i.top}</svg>`.replace(/{\s?([^{}\s]*)\s?}/g,((t,e)=>i[e]))){return i.innerHTML=1==i.img?
`<img src="data:image/svg+xml,${c.replace(/#/g,"%23")}">`:c}})})(
{
   menu:"box:9;path:m1.5 2.8h6m0 2h-6m0 2h6,stroke-linecap='round'",
   settings:"box:96;<circle stroke-width='12' cx='48' cy='50' r='26'/><circle stroke-width='12' cx='48' cy='50' r='36' stroke-dasharray='14'/>",
   renew:"box:96;fill:black;path:M48 24v12l16-16-16-16v12c-18 0-32 14-32 32 0 6 2 12 5 17L27 60A23 23 0 0 1 24 48c0-13 11-24 24-24zm26 6L69 37c2 3 3 7 3 11 0 13-11 24-24 24v-12l-16 16 16 16v-12c18 0 32-14 32-32 0-6-2-12-5-16z"
});
</script>

<style>
  svg-icon {
    width: 80px;
    display: inline-block;
    background: grey;
  }
  svg-icon:hover { background: lightgrey; cursor:pointer }
</style>

<svg-icon is="menu"></svg-icon>
<svg-icon is="settings"></svg-icon>
<svg-icon is="renew" rotate=45 fill=gold stroke=white></svg-icon>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to alter the background behind each word in a text using only CSS?

I have a question about styling quotes by highlighting each word in the text with a background color. The issue I'm facing is that when using a solid background, there are no gaps between the colors. How can I achieve a result similar to this, but wit ...

Does the built-in waiting mechanism in Protractor automatically handle promises?

While browsing through Stack Overflow, I stumbled upon this response in a discussion about Protractor tests and asynchronous solutions: 'AFAIK expect waits internally for the related promises.' I have tried looking through the official Protract ...

Concealing content to prevent it from being accessed through HTML and JavaScript inspection techniques

I created a website with a simple guessing game where users can win if they enter the right code. My approach involves using JavaScript: <script> function z() { var b = document.getElementById('idea'); var a = document.g ...

Simplest method for defining an associative array

Looking to create an array in the format shown below: [0: 0, 1: 1, 2: 2] This is achieved using the following code snippet: var arr = []; for(i=0; i<3; i++){ arr[i] = i; } Upon execution, my array appears as follows: [0, 1, 2] The values with ...

The XPath for the element that comes before a specific text

Looking for the XPath of the following code snippet: <a class="account-name" long-text="Sample Text" ng-click="accountClick(account)" ng-href="sample URL" href="sample URL1"> <span>Plan Name</span></a> I attempted this: //span[te ...

A guide to activating an input field based on the value of another input field in AngularJs

An AngularJs form requires the user to input the number of hours worked. If the value entered is 0, an additional question should be displayed for the reason why no work was done. <label>Hours worked:</label> <input ng-model="hours" type="n ...

Can you point me in the direction of some resources for developing a custom plugin with stylelint?

After visiting the stylelint website and github, I downloaded it locally using npm. The stylelint website suggests using the following format to create my own plugin: var myPluginRule = stylelint.createPlugin(ruleName, function(primaryOption, secondaryOpt ...

"Receive your share of the catch in a pop-up notification

Is there a way to determine if a user shared a result without using the social network's Javascript SDK? All sharing aspects (authorization, sharing, etc.) are done through popups on my domain. var popup = window.open('/api/share/' + servic ...

I'm confused as to why I keep receiving alert messages every time I click on a button. Can someone please provide

My aim is to enhance the functionality such that clicking the blue button changes the reading status to either <Yes> or <Not>. Any guidance on this would be greatly appreciated. Additionally, I am puzzled as to why, currently, I receive an aler ...

Utilizing Next.js - Implementation of a unique useThemeMode hook to efficiently manage theme preferences stored in the browser's localStorage, seamlessly integrating with toggleTheme

For a while now, I've been trying to figure out how to toggle my favicon based on the theme logic of my application and the current theme state stored in localStorage. My approach involves using CSS variables and data attributes applied to the html bo ...

Displaying a pop-up message over the "Login button" for users who are not currently logged in

I am currently in the process of developing a website using node.js and express. I have successfully integrated all the login functionality through passport, allowing users to easily log in or out by utilizing res.user. However, I now want to enhance the ...

contrasting module export approaches

Let me clarify that my query does not revolve around the disparity between module.exports and exports. Instead, I am interested in understanding the contrast between exporting a function that generates an object containing the functions to be shared upon i ...

What could be the reason for Chrome breaking up this straightforward bootstrap header into two lines?

Why is it that the code below displays correctly in one line in both FF and IE, but Chrome for some reason is showing it on two lines as if both span and button elements had "display:block;"? Even though the button has a computed display of "inline-block," ...

Prevent the submission of the form if the textfield does not contain any

Is there a way to prevent form submission when a textfield is empty? Currently, my script allows for new empty records to be inserted into the database even when the textfield is empty. $(document).ready(function(){ $("#form1").on('submit', ...

Launch an Android application directly from a web browser upon the webpage's loading

When a user visits www.example.com/myApp, I want my app to open automatically without any click required. I have attempted the following methods: window.onload = function () { window.location.replace("intent://something#Intent;scheme=myapp;packag ...

exploring the digital archives for a specific song file on the computer

Currently in the process of building a website, and I am looking to incorporate a search and filter feature for all music content so that users can play it on my player. Wondering if this is possible? Seeking some assistance and creative ideas to make thi ...

Difficulty with navigation buttons on multiple Bootstrap carousels implemented using ngFor in a single page

Currently, I'm engaged in developing a practice eCommerce platform where multiple product cards are showcased using data from a sample JSON file. Additionally, several Bootstrap carousels are integrated into the website to display images of each item. ...

Leveraging the ReactJS Hook useState for detecting Key press events

As I am in the process of constructing a piano, I want it to showcase certain CSS styles when the user "presses" specific keyboard buttons (via keydown event) - even enabling the simultaneous clicking of multiple different buttons. Once the user releases t ...

Ways to retrieve an HTML form

I have designed an HTML form that submits data to addstuds.php for inserting records into a MySQL database. <form name="formcheck" method="post" action="addstuds.php"> <td width="30" height="35"><font size="3">*ID Number:</td> < ...

Implementing multiple modules within a shared parent route in Angular

Currently, I am seeking a method to load multiple modules under the same path in Angular. Let's say I have three modules: AModule, BModule, and CModule, each with its own RouterModule.forChild call. My goal is to combine these modules under the route ...