Tips for optimizing SVG icon caching on an external CDN without encountering flash of missing icons

I've mastered the process of getting SVG icons to load on my website, but I am facing a challenge in meeting all the criteria listed below:

  1. Need to be able to use SVG icons in CSS
  2. Avoid any flash of missing icons (FOMI)
  3. Minimize the initial page size
  4. Ensure cached SVGs
  5. Ability to utilize a CDN
  6. Must support fill: currentColor for consistent text color matching, similar to icon-fonts
  7. Bonus: Implement Pixel-aligning the SVGs for sharp appearance

To meet criteria 1, 2, 3, and 4, we can use an external sprite map as shown below:

<svg viewBox="0 0 100 100">
    <use xmlns:xlink="http://www.w3.org/1999/xlink"
         xlink:href="/assets/sprite-4faa5ef477.svg#icon-asterisk-50af6"></use>
</svg>

However, due to the ongoing CORS issue with browsers (read more here), using a CDN is currently not possible.

We could potentially address this by implementing patches for support on external domains. Yet, this solution may not benefit CSS since it primarily monitors the DOM. Additionally, it triggers numerous failed requests to inaccessible files, one for each icon on the webpage.

If we intend to leverage a CDN, alternative methods such as inline SVG insertion (increasing page size without caching) or AJAX loading (leading to FOMI) can be considered.

Hence, are there any viable solutions that fulfill all 5 7 requirements?

In essence, I aspire for SVGs to offer the same convenience as icon-fonts; otherwise, the transition seems futile. While SVGs allow for varied colors and enhanced accessibility, achieving an optimal aesthetic and efficient loading has proven challenging.

Answer №1

My solution involves loading an SVG in an image element and utilizing it as an "old-school" image sprite, which appears to meet all the specified criteria. The only drawback is the potential loss of being able to modify specific sections of the SVG using CSS. However, this limitation does not seem to be a constraint in this case, and it is still possible to customize the entire icon, as demonstrated in my sample. I have even provided a fiddle and included a code snippet for reference.

In order to replicate a CDN setup, I created an SVG file and uploaded it to an image hosting service. If that service is no longer available in the future, I apologize to readers. The SVG file contains all icons grouped together (currently a black square, circle, and triangle). Unlike SVG sprite maps, the icons are embedded within the SVG itself rather than in the defs section. Combining multiple SVGs into one should be relatively straightforward, although I haven't explored tools to automate this process.

.icon {
  display: inline-block;
  vertical-align: top;
  width: 30px; /* adjust as needed */
  height: 30px;
  background-image: url('http://imgh.us/icons_36.svg');
  
  border: 1px solid #000; /* for visual aid */
}

/* sizes */
.icon.large {
  width: 50px;
  height: 50px;
  background-size: 150px auto;
}

/* positioning */
.icon.circle { background-position: -30px 0; }
.icon.large.circle { background-position: -50px 0; }
.icon.triangle { background-position: -60px 0; }
.icon.large.triangle { background-position: -100px 0; }

/* styles */
.icon.info {
  filter: invert(100%) sepia(100%) saturate(50000%) hue-rotate(90deg) brightness(70%);
}
.icon.highlight {
  filter: invert(100%) sepia(100%) saturate(10000%) hue-rotate(30deg) brightness(50%);
}
<span class="icon square"></span>
<span class="icon circle"></span>
<span class="icon triangle"></span>
<span class="icon circle highlight"></span>
<span class="icon triangle large info"></span>

Answer №2

To handle this situation, my recommendation is to implement data uris, as they enjoy excellent support from browsers. Tools like Grunticon or their online service Grumpicon can be helpful in this process.

This approach will generate 2 css files and 1 js, which can easily integrate with your Content Delivery Network (CDN).

The final output offers great flexibility and options for customization.

Answer №3

I was facing a similar issue and came up with an unconventional solution that may not fully meet the FOMI requirement. It's actually a clever hack that helped me out of a tough spot. Essentially, this script replaces every img element in the DOM that includes an svg with inline SVG, allowing for customization of styles.

// This script swaps img tags with svg tags if they contain an svg source
// Enables direct manipulation of SVGs in the DOM
// 💡 Returns a Promise to execute tasks after fetching SVGs

let fetchSVGs = () => {

// Retrieves the SRCs of all SVGs
let parentImgs = Array.from(document.querySelectorAll('img')).map((img) => {
    if(img.src.endsWith('.svg')) {
        return img
    }
});

let promises = [];
parentImgs.forEach((img) => {
    promises.push(
        fetch(img.src).then((response) => {
            // Error handling
            if (response.status !== 200) {
                console.log('Looks like there was a problem. Status Code: ' +
                    response.status);
                return;
            }
            // Saves the SVG
            return response.text();
        })
    )
});

// All fetch() calls have been made
return Promise
    .all(promises)
    .then((texts)=> {
        texts.forEach((text, i) => {
            let img = parentImgs[i];

            let div = document.createElement('div');
            div.innerHTML = text;
            img.parentNode.appendChild(div);
            let svg = div.firstChild;
            img.parentNode.appendChild(svg);

            // Makes the SVG inherit the class from its parent
            svg.classList = img.className;

            // Removes unnecessary elements
            div.remove();
            img.parentNode.removeChild(img);

        })
    })
    .catch((error) => {
        console.log(error);
    })
};

On another note, I discovered a neat trick on Twitter today https://twitter.com/chriscoyier/status/1124064712067624960 where applying this CSS to a div allowed me to create a customizable svg icon that can be stored in a CDN

.icon-mask {
  display: inline-block;
  width: 80px;
  height: 80px;
  background: red;
   -webkit-mask: url(https://cdnjs.cloudflare.com/ajax/libs/simple-icons/3.0.1/codepen.svg);
   -webkit-mask-size: cover;
}

Keep in mind that browser support for this technique is not yet universal.

I hope this information proves helpful to someone! 😄

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

using CSS to position elements that are generated dynamically

Hey there, I'm facing a little issue with my elements. These elements are being generated dynamically and I'd like to display them in a 4 column layout. The challenge is that they arrive separately and I can't simply wrap them in a div and u ...

Encase every picture within a div and add a numerical label in front of it

I'm working on a function that will wrap each image in a div and add a span label for each image. Here is the code I have written so far: $('#carousel img').each(function(index) { $(this).wrap('<div class="image"></div>& ...

Can you use "or" or "not" syntax with CSS input type selectors?

In the world of programming, if they actually exist, Suppose I have created an HTML form with the following input fields: <input type="text" /> <input type="password" /> <input type="checkbox" /> I wish to style all input fields that a ...

Ways to create a fading effect on an image without the need for an additional div

I am facing an issue with a page that displays product images. Whenever I hover over an image, it enlarges slightly but the max-height remains unchanged. To enhance this effect, I want the image to fade out on all sides rather than showing a white backgrou ...

"Looking to spice up your website with a dynamic background-image

I've encountered a problem with my CSS code for the header's background image. Despite trying various methods to create a slideshow, nothing seems to be working. Can someone provide guidance? I have four banner images named banner1, banner2, bann ...

What are the best methods for extracting real-time data from Yahoo Finance streaming services?

Yahoo finance streaming employs a unique method where a file gradually grows in size to continually update their data: ^FTSE Is there a way for me to gather this data (I have no intention of selling it- just looking to create my own beginner trading dash ...

Having issues with $_POST not retrieving values from .post

Below is the javascript snippet that I have written: function submitForm() { var name = document.getElementsByName('name').value ,email = document.getElementsByName('email').value ,subject = document.getElementsBy ...

The content of XMLHttpRequest is accessible via the property response

Typically, when we want to retrieve data using AJAX, we would use code like this: var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ elem.innerHTML = xhr.responseText; ...

Update the .erb code with Ajax after successfully creating the object

What is the best way to use Ajax in Rails 4 to automatically refresh the code in ".erb" files after successfully creating a new "Box"? The relevant file is located in: views/modifications/show.html.erb <tbody id="boxes_count"> <% @modificat ...

Incorporating .json files into an HTML template with the help of an HTML form designed for selecting a particular

I am faced with a collection of various .json files that I wish to specify by name on an HTML page (local) form, enabling me to load this data onto a table. This is how my HTML form appears: <form> File: <input type="text" Id="file_name"&g ...

utilizing the 'v-for' directive for creating a stylish CSS grid

I am having trouble getting these images to display horizontally on the preview instead of vertically. I attempted using display grid in the CSS, but they still show up vertically. Can someone please help me figure out what I am missing? Essentially, when ...

Guide to implementing the onchange event in JavaScript for this specific scenario

How can the onchange event be utilized in this scenario using JavaScript? First, input data into the input with id="one". Subsequently, the data in the input with id="two" will be updated to match the data in the input with id="one". However, when the da ...

Achieving Equal Column Height and Proper Margins in Bootstrap 4: A Comprehensive Guide

I am looking to enclose my elements in a rectangular container with rounded borders and a box shadow, while ensuring they have consistent height and are responsive (this is why I do not define max height or height directly) Here's the desired end res ...

Changing the size of an image in an HTML5 canvas

I have been attempting to generate a thumbnail image on the client side using Javascript and a canvas element. However, when I reduce the size of the image, it appears distorted. It seems as though the resizing is being done with 'Nearest Neighbor&apo ...

What is the reason for browsers changing single quotation marks to double when making an AJAX request?

Jquery: var content = "<!DOCTYPE html><html lang='en'><head><meta charset='utf-8'><meta http-equiv='X-UA-Compatible' content='IE=edge'><meta name='viewport' content='w ...

Resource loading failed due to the XMLHttpRequest restriction

I am attempting to create a basic php backend for managing a contact form on another server. Despite adding the correct headers, I keep encountering the same error message: XMLHttpRequest cannot load https://php-contact-form-lual.herokuapp.com/. No ' ...

When making an asynchronous call, only the initial character is shown in the (HTML) listbox elements

I have a query regarding AngularJS compatibility with IE9. My issue is with a modal window containing a patient list. <div class="modal-header"> <h3 class="modal-title">Patient list</h3> </div> <div class="m ...

Tips for reducing the impact on performance caused by cookie consent code

Experimenting with basic HTML to analyze the impact of cookie consent code. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="determine page l ...

When completing a form submission, make sure to eliminate the %5B%5D from the

Whenever I submit a form with multiple checkboxes that share the same name, the resulting URL format is as follows: www.example.com/search.php?myvalue%5B%5D=value1&myvalue%5B%5D=value2 Is there a method to eliminate the %5B%5D in the URL and make it m ...

How do I insert a variable into my email content using PHP?

Hey there, I have a form that captures Name, Email, Subject, Telephone Number, Message, and a checkbox. Unfortunately, I'm not very proficient in PHP. I've just started learning the basics and could use some guidance from you :) The Form < ...