In this article you’ll learn how to use an SVG as a favicon for your website, considering the light and dark theme detection in the browser using the CSS prefers-color-scheme media feature.

A website with SVG favicon for both light and dark themes

Summary

How to add a favicon to your website

A favorites icon, also known as a favicon, is a tiny icon associated with a particular web site or web page that is displayed usually in browser’s address bar and bookmarks menu.

The favicon is used to improve the user experience and enforce a brand’s consistency. When a familiar favicon is seen in the browser’s address bar, for example, it helps users to know they are in the right place. This is how phishing in the browser usually succeeds but that’s a completely different story.

Here are the image formats you can use to add a favicon to your website. Spoiler alert: there is no one-size-and-format that fits in all the browsers. There would have been too easy!

  • ICO - the ancient default
  • GIF - for when, you know, want to draw attention within a plethora of open tabs
  • PNG - all browsers support the .ico format but the PNG format might be handy
  • SVG - the higher resolution approach that has worse browser support but lots of potential

In this article, we’ll be focusing on the latter approach that is based on using the Scalable Vector Graphics (SVG), as it teams up perfectly with the CSS prefers-color-scheme media feature.

Light & Dark theme detection in the browser

We don’t know for sure yet why most developers prefer to use dark themes in general but some say it’s comfortable on the eyes while others find it more exciting. Also, there’s the category below:

― Why do programmers prefer dark mode?
― Cause light attracts bugs.

from r/Jokes

CSS detection

You can enable CSS theme mode detection with CSS prefers-color-scheme media feature, in order to add an alternative look and feel to your website with custom CSS rules:

@media (prefers-color-scheme: dark) {
  /* "Give yourself to the Dark Side" - Darth Vader */
}

JavaScript detection

According to MDN, the Window’s matchMedia() method returns an object that represents the result of the specified media query string.

The dark mode or dark theme has made its way to the main headlights for some time, so here’s how to detect the darkness with JavaScript:

if (window.matchMedia &&
    window.matchMedia('(prefers-color-scheme: dark)').matches) {
  // “Fear is the path to the Dark Side" - Yoda
}

Although the above is a possible and working solution for switching the favicon in the HTML, I wouldn’t recommend it, as now you can do that without JavaScript at all.

How to switch the SVG favicon when in Dark Mode

First, add the SVG favicon to your HTML <head> section:

<link rel="icon" href="/favicon.svg" type="image/svg+xml">

Regarding the SVG favicon.svg’s inner content, below is a rough example of an SVG rectangle with rounded corners, which has a different color, depending on the active theme. The detection is made using the above CSS prefers-color-scheme media feature.

<svg width="50" height="50" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
  <style>
    rect {
      fill: green;
    }
    @media (prefers-color-scheme: dark) {
      rect {
        fill: red;
      }
    }
  </style>
  <rect width="50" height="50" rx="5"/>
</svg>

Browser support and fallbacks

Considering the current browser support for the SVG favicon, a fallback is required. In this case, we serve the PNG format when the browser fails to accept SVG as a favicon.

If the user agent tries to use an icon but that icon is determined, upon closer examination, to in fact be inappropriate (e.g. because it uses an unsupported format), then the user agent must try the next-most-appropriate icon as determined by the attributes.

from WHATWG docs

The common approach when it comes to older browsers that support neither the PNG favicon format is to keep a favicon.ico file in the root. Careful not to <link> to it within the <head> section at all because doing that will result in browsers picking the favicon.ico as the default.

<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="icon" href="/favicon.png" type="image/png">
<!-- favicon.ico in the root -->

With that being said, after testing this in all the existing modern browsers, here is the order the browsers will look for the favicon, with the code above:

  1. SVG (hopefully!)
  2. PNG (no worries, this is good too!)
  3. ICO (oh, here we go again!)

Yes, lots of browsers, because we have to love them all!

Modern browsers icons

Read more

You might want to read more on SVG, favicons and CSS media features: