skip to Main Content

I have a SVG image that I plan to reuse 50 – 150x times in my page, and as the page would be an infinite scroll, it could appear 1000x times or more

It is an upvote icon. I think of using the same icon, reversed, for a downvote

What is the most efficient way to include it ?

  • Create a single file, link to it in an img tag, and use CSS to reverse it for downvotes ?
  • Include the SVG code every single time ?

Will the HTML somehow optimize automatically the SVG code if seen many times in a page ? Or is it better to include SVG as code than as img tags ?

3

Answers


  1. Chosen as BEST ANSWER

    Ok so actually with the <img> tag it seems better as it is cached as drEr suggested in comments also in

    When multiple instances of same images are embedded in an HTML, does that load the image once?

    Multiple image <img> tag with same source src

    So I think I will go with the <img> tag


  2. Why waste CPU time on elements that are not in the viewPort (yet)

    You can use: <img loading="lazy" src="[YOUR SVG]">

    "lazy" defers loading the image until it reaches a calculated distance from the viewport, as defined by the browser. The intent is to avoid the network and storage bandwidth needed to handle the image until it’s reasonably certain that it will be needed. This generally improves the performance of the content in most typical use cases.

    And yes, if it is the same src then the image is cached.

    <svg-vote> Web Component with IntersectionObserver API

    Or, for more control like adding a EventListener and tracking how a user scrolled,
    use a Web Component that only draws an SVG when it becomes visible in the viewPort using the IntersectionObserver API

    https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver

    Note: this does need JavaScript; for a non-JavaScript solution, see ccprog his answer.

    <script>
      customElements.define('vote-svg', class extends HTMLElement {
        connectedCallback( is = this.getAttribute("is") ) {
          (new IntersectionObserver((entries, observer) => {
              if (entries[0].isIntersecting) {
                console.log("render", this.nodeName, this.id, is || "up");
                this.innerHTML = 
                  `<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">` +
                  `<circle cx="50" cy="50" r="45" stroke="black" fill="white" />` +
                  `<polygon ${is=="down" ? "transform='rotate(180 50 50)'":""} points="50 10 15 70 85 70" stroke="black" fill="green" />` +
                  `</svg>`;
                this.onclick = () => console.log("clicked", this.id);
                observer.unobserve(this);
              }
          })).observe(this);
        }
      });
    </script>
    
    <style>
      vote-svg { width:100px; height:100px; display:inline-block;cursor:pointer }
      hr { height:20em; background:pink }
    </style>
    <vote-svg id="msg001"></vote-svg>
      <hr>
    <vote-svg id="msg042"></vote-svg>
      <hr>
    <vote-svg id="msg555" is="down"></vote-svg>
      <hr>
    <vote-svg id="msg666" is="down"></vote-svg>
      <hr>
    <vote-svg id="msg999" is="up"></vote-svg>
      <hr>
    Login or Signup to reply.
  3. As long as the icon source code isn’t too complicated (containing filters, animations or interpolation tasks like color gradients), rendering performance should not be much of an issue, regardless of method used.

    Loading times over the net also can be minimized with loading the icon code only once, or better yet, as part of another file loaded anyway. So adding the code once inside the HTML code, a script or a stylesheet for reuse might give you a tiny advantage over using an <img> tag.

    But note that the time at which the icon becomes available for rendering might differ depending on whether you use script or stylesheet, and what priority you set via preload and related attributes. Especially if you use a bulky JS framework, time to first render might be significantly delayed for a Component.

    The most elegant technique for embeding the icon in script is the Web Component, as shown in Danny Engelman’s answer.

    Embedding in HTML code would need a hidden <svg> element somewhere on the page:

    <body>
      <svg width="0" height="0" display="block">
        <symbol id="vote" viewBox="...">
          <path d="..." fill="#080" />
       </symbol>
     ...
    </body>
    

    a bit of CSS:

    .icon-vote {
        display: inline-block;
        position: relative;
        width: 1em;
    }
    .icon-downvote {
        transform: rotate(180deg);
        transform-origin: center;
    }
    

    and some code to reference the template:

    <svg class="icon-vote"><use href="#vote" /></svg>
    <svg class="icon-vote icon-downvote"><use href="#vote" /></svg>
    

    Embedding in a stylesheet would take advantage of a data url (note the URL escape of the #):

    .icon-vote {
        display: inline-block;
        position: relative;
        width: 1em;
        background: url('data:image/svg+xml,<svg viewBox="..."><path d="..." / fill="%23080"></svg>');
    }
    .icon-downvote {
        transform: rotate(180deg);
        transform-origin: center;
    }
    

    For usage, that would only need

    <span class="icon-vote"></span>
    <span class="icon-vote icon-downvote"></span>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search