OMG, SVG Favicons FTW!

This article explores the world of SVG favicons. We cover adding them to HTML, using emojis, inlining them as data URIs, supporting dark mode, and animations.

Chinese Version / δΈ­ζ–‡η‰ˆ

I’ve been working on some side projects recently (Style Check and bedrocss), and as with any project I work on long enough, I got to the point where I wanted to add a favicon.

I decided to play around with SVG favicons. The support is just ok (boo Safari) but it’s good enough for my needs. I’m alright if no favicon shows up on unsupported browsers. It’s not the end of the world. And in fact, you can get around this issue (see the caveats below).

By using an SVG, I’m able to get a lot of cool benefits like:

  • Crisp image quality with a single file
  • Support for emojis
  • Inline icon (no need for a linked resource)
  • Dark mode detection (sweet!)
  • Animated favicons

Let’s dig into adding SVG favicons to your project. For the following examples (besides emojis), we’ll use a very basic circle SVG:

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>
  <circle cx="50" cy="50" r="50"/>
</svg>

Adding An SVG Favicon To HTML

The syntax for adding a favicon to your website hasn’t changed in a long time, and the same applies for SVG favicons (minus the file extension).

In your HTML file’s <head> tag you place a <link> element with the rel attribute set to “icon” and the href attribute set to the path where your icon lives.

<link rel="icon" href="path/to/favicon.svg"/>

Because we are using an SVG, the icon can be whatever size you want, just make sure that the canvas is square.

If you need to search for free icons, icones is a good resource, or you can create your own with penpot.

Inlining SVG Favicons As Data-URI

After switching to SVG favicons, the first thing I tried to do was to see if I could use them with an inline format rather than linking to a separate file.

I’ve used the Data-URI trick before with inline images or backgrounds and it works like a charm. Good news, it also works for favicons.

Instead of linking to the path, prefix your entire SVG code with data:image/svg+xml;utf8, (including that last comma) and pass the whole thing to the href attribute.

<link rel="icon" href="data:image/svg+xml;utf8,<svg...>...</svg>">

I really like this method because I can just forget about placing the icon file in a folder somewhere, and I can copy/paste this code to any project (most of my side projects use the same icon now).

You could argue against using an inline SVG favicon because linking to a file can be cached, and adding the inline SVG on every page would increase the HTML size, but I don’t think it would make much difference, and I prefer the maintainability here.

If you only have one website to deal with, this may not be a big deal, but as someone that maintains several sites and uses the same favicon, this is great.

It’s also worth pointing out that being able to inline the favicon is not unique to SVGs. You can do it with all sorts of other image formats, but the real difference, in my opinion, is how much easier it is to do with SVG. I can even do it by hand.

Using An Emoji For Your Favicon

A while back a tweet by Lea Verou showed how they can be used to add emojis as favicons. I probably never would have even thought of that, but it’s pretty straight forward.

The syntax works the same before. Since SVGs support text content through the <text> element and emojis are pretty much text, you can put any emoji inside your SVG (it may need some moving around to fit right).

<link rel="icon" href="data:image/svg+xml,<svg xmlns="http://w3.org/2000/svg" viewBox="0 0 100 100">
<text y=".9em" font-size="90">πŸ’©</text>
</svg>" />

(LOL, it’s poop!)

This makes it really easy to have a favicon without creating a custom one. Want something even easier? Check out emojicon.dev by Bryson Reece. It gives you a list of emojis, and you can click on any one of them to copy the whole favicon snippet to your clipboard.

If that’s nor your jam, Wes Bos also created fav.farm. It’s a 3rd party service that will generate the favicon for you. You can link directly to his service with the emoji you want.

<link rel="icon" href="https://fav.farm/πŸ’©" /> 

The creativity of the dev community never ceases to impress me. So many cool, smart, and creative devs out there.

Adding Dark Mode Detection

We can add a <style> tag to our SVG and use the prefers-color-scheme media query to change our icon based on the user’s dark mode preferences.

<link rel="icon" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>
  <style>
    svg {
      background: white;
    }
    circle {
      fill: black;
    }
    @media (prefers-color-scheme: dark)  {
      svg {
        background: black;
      }
      circle {
        fill: white;
      }
    }
  </style>
  <circle cx="50" cy="50" r="50"/>
</svg>">

In this example, I’m targeting the SVG and <circle> directly, but you could just as well use classes. For custom SVGs, you’ll probably need to do that.

The <style> tags in the SVG are contained within that XML document, so you don’t have to worry about styles leaking into the rest of your application.

Animated Favicons

As we saw above, we can use CSS in our SVG. This means that we could, in theory, add animations to our favicon as well.

However, we don’t actually need CSS animations to do this because SVG has animation built in via the <animate> tag.

For example, we could create a square and animate the corner radius over 5 seconds to make it look like a circle.

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
  <rect width="100" height="100">
    <animate attributeName="rx" values="0;50;0" dur="5s" repeatCount="indefinite" />
  </rect>
</svg>

How cool is that!? I mean the concept. The example is kind of boring, but you get the idea.

Caveats

Of course, nothing is perfect, so let’s look at the tradeoffs here. As mentioned above, the support is not quite ready for production, but you can get around that by also including a fallback to a /favicon.ico before your SVG version.

Another issues stems from inlining the favicon. I mentioned it above, but it’s worth reiterating here. When you inline an asset, that asset will not be stored in the cache. If you load it as a file, it will be. So the first page a user goes to might be faster (due to one less HTTP request), but for every other page they visit, they will need to download a larger HTML file (for the inline asset) when they could have just pulled the favicon from their cache.

The last point I think is worth mentioning is also performance related. In the majority of cases I’ve run into building websited, an SVG will be a much smaller file size than a corresponding PNG. However, since PNG files are raster based and favicons are generally small in dimension, a PNG (or ICO) favicon might lead to a smaller file size. It really depends on how complicated the icon is, so if that’s something you are very concerned about, simply test the two options.

Closing Thoughts

Hopefully you found this interesting or useful. I know I had fun tinkering with SVGs for my projects. Here’s the final version of my favicon in case you’re interested:

<link rel="icon" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 500 500'><style>svg{background:white;}path{fill:black;}@media(prefers-color-scheme:dark){svg{background:black;}path{fill:white;}}</style><path d='M246 411l5 32c2 9-1 16-8 20l-14 8-14 8c-8 3-16 4-23 0-8-3-13-9-16-19l-10-38a880 880 0 01-11-65l-3-25c0-5-2-8-3-10-2-2-6-3-10-3l-55-2c-6-1-10 0-13 2s-7 6-8 12l-15 46-16 47-3 9-3 10-1 4-3 5c-2 4-6 7-11 9s-10 2-15 0c-3-1-5-3-5-4l-1-5 1-5 1-5 19-55 19-55 1-3 1-4c3-6 0-9-7-8h-61l-5-1c-2 0-2-2-3-4l-4-14-1-5c-1-13 5-20 17-20l36-1 35 1c6 0 10-1 13-3s5-5 7-10l19-43 20-41a1373 1373 0 0145-87c2-7 2-14 2-20l2-19 2-18c0-10 6-15 15-15h16l14-1h-1 1v1l-1-1 1 7-1 6c-4 10-5 20-5 30a516 516 0 001 32v3l1-3 1-1c5-6 8-12 8-20 0-6 1-13 3-19l1-7 1-5c2-4 5-6 9-6 3 0 5 2 7 6l4 11 2 12 1 54v55l2 52 2 52 3 9c1 2 3 5 7 7 3 2 5 5 7 9l3 12 2 11c0 4-4 7-10 8-2 1-3 2-3 5l-2 7 4 34 4 34zM139 281c7 1 10-2 10-9V144l-1-4-2-2-3 2-4 2v3l-2 2-24 58-24 58c-2 4-2 7 0 9 1 2 4 3 8 3l21 3 21 3zm60-183l-1 1h1v-1zM-15 434c0 6 1 9 7 8l-7 2c-3 1-3 4-1 8 1 1 0 2-2 3l-3 2a7231 7231 0 01-6-5l9-29 9-29 2-2 1-1v6l-4 18-5 19z'/><path d='M516 209a1308 1308 0 00-33 253c0 7 3 13 7 19-4 0-7-2-7-4l-3-8c-3-14-5-29-6-44l-1-43 4-44-4 1-2 3-4 54c-2 18-1 36 2 54 2 13 6 24 11 34 4 8 2 13-5 15-7 3-15 3-23 1-9-3-16-7-20-13-6-8-10-16-12-25l-6-27-1-9-1-9-3-1h-4l-6 9-6 8-16 19-17 18c-5 5-10 9-16 11-6 3-13 3-20 1l-17-1-17 1c-26 5-47-4-63-27-10-14-17-30-22-45-4-15-6-32-6-50 2-100 32-190 91-269 12-16 26-30 40-42 15-13 31-22 51-28l18-5 18 1 32 8 31 11 8 6 6 9c2 1 2 3 2 6v6l-6-1h-10c-3 4-7 6-11 5l-10-5-8-6-10-5-11-2-7 1c-18 12-34 27-49 45a462 462 0 00-84 348c17-10 32-24 48-41a547 547 0 0077-115l29-50c1-2 1-2-1-1l-7 3-7 3c-1 1-2 1-1-1l-1-1 1 2-5-2-6-1 23-24c-9-1-17 3-22 8l-17 19c-3 3-6 5-10 6a26 26 0 01-23-4c-4-3-7-6-8-10-4-8-3-15 3-20l6-5 5-4 44-23 46-22c10-4 19-4 27 1s15 13 19 24l1 5 6 10-1 9zm-8-6l-1 2h-1l1 1v-1l1-2zM271 329l-3 4c-1 3-1 5-3 7l3-2 2-4 1-2v-3zm-6 11l1 2v2l1 6 2-1h1l-1-3-2-3-1-2-1-1zm6 50v-4l-1-4 2-1-3-8-3-6v15l2 8 2 4 1-4zm2 24l2 3-1-7-1-1h-1v2l1 3zm0-106l2-8v-1l-3-3v10l1 1v1zm6-33v1-1zm82 151l1 1-1-1zm79-212h-1 1zm56 30l-3-2v5c0-2 1-3 3-3zm-17 66l-2 1-2 10v10l2 5 1-3 1-3v-20zm1-10l3-5 4-21 3-20-5 20-5 21v5zm-68-55l-2-1 5-4-2 2-1 3zm3-5l1-1h1l-2 1zm85 236h1l-1 1v-1z'/></svg>">

You can find it publishes on projects like bedrocss, Vuetensils, and Style Check. Check it out in dark mode too!

Thank you so much for reading. If you liked this article, and want to support me, the best ways to do so are to share it, sign up for my newsletter, and follow me on Twitter.


Originally published on austingil.com.

Leave a Reply

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