Favicon Builder

How to Make a Favicon for Dark Mode

Published December 7, 2025 · Updated June 9, 2026

The cleanest dark-mode favicon is a single SVG with a prefers-color-scheme media query inside it that recolours the artwork. One file, no JavaScript.

The cleanest way to make a favicon that adapts to dark mode is a single SVG favicon with a @media (prefers-color-scheme: dark) block inside it that recolours the artwork. No second file, no JavaScript, no media attributes on your <link> tags. The browser reads the OS theme and the SVG repaints itself. You keep your favicon.ico and PNG as fallbacks for browsers that don’t render SVG favicons (mainly Safari), so every visitor sees a readable icon either way.

In one line: put the media query inside the SVG, not the HTML — one file recolours itself.

The reason this matters: a dark navy logo on a transparent background looks fine on a white tab strip and then vanishes the moment the browser chrome turns charcoal. A white glyph does the opposite. Dark mode is the default on a large share of devices now, so an icon that only reads on one background is invisible to roughly half your audience.

Why a dark-mode favicon is worth doing

Browser tabs, bookmark bars, and history lists all inherit the OS or browser theme. When that surface goes dark, your favicon sits on a near-black background instead of white. Two failure modes follow:

You don’t always need a dual icon. If your mark is already high-contrast against both backgrounds — say a bold coloured shape with a light glyph inside it — one version is enough. Drop it onto a #ffffff canvas and a #0f172a canvas; if it reads clearly on both, you can stop here. If it disappears against one, you need the SVG technique below.

The SVG media-query method (preferred)

An SVG favicon is just a small XML document, and it can carry its own <style> block. Put a prefers-color-scheme media query in that style block and the icon recolours itself when the OS switches theme. Here’s a complete, working example:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  <style>
    /* Light mode (default): dark mark */
    .mark { fill: #0f172a; }
    /* Dark mode: light mark */
    @media (prefers-color-scheme: dark) {
      .mark { fill: #f8fafc; }
    }
  </style>
  <rect class="mark" x="6" y="4" width="6" height="24"/>
  <rect class="mark" x="6" y="4" width="16" height="6"/>
  <rect class="mark" x="6" y="14" width="13" height="6"/>
</svg>

That draws a simple “F” that is dark slate on a light background and switches to near-white when the system is in dark mode. Save it as favicon.svg, put it in your site root, and reference it with the standard tag:

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

A few things make or break this technique:

This is the modern default, and it’s exactly what most generators (including the one below) emit. For where SVG favicons fit in the wider format picture, see SVG Favicons – When to Use Them & Browser Support.

Generate the SVG (and the fallbacks) in one step

Hand-writing the SVG works, but the file only solves dark mode in browsers that render SVG favicons. You still need a multi-size favicon.ico and an Apple touch icon as fallbacks, all sharing the same artwork. FaviconBuilder takes one upload and outputs the complete set — including the SVG with the dark-mode media query baked in — plus the copy-paste HTML and manifest. It’s free, needs no account, and your image never leaves your browser. Upload an SVG (preferred) or a PNG/JPG at 512×512 or larger and you get the whole package back.

The older JavaScript method (fallback for raster icons)

If your icon is a raster PNG and you can’t use a single recolouring SVG, you can swap the <link>’s href with JavaScript when the theme changes. Listen on a matchMedia query and point the icon at the matching file:

<link id="favicon" rel="icon" href="/favicon-light.png" type="image/png" sizes="32x32">
<script>
  const link = document.getElementById('favicon');
  const dark = window.matchMedia('(prefers-color-scheme: dark)');
  const setIcon = () => {
    link.href = dark.matches ? '/favicon-dark.png' : '/favicon-light.png';
  };
  setIcon();
  dark.addEventListener('change', setIcon);
</script>

This works in any browser that runs JavaScript and supports matchMedia (effectively all of them), and it updates live when the user toggles their theme. The trade-offs: it requires two exported PNGs, it doesn’t run if scripting is disabled, and the swap happens after first paint, so there can be a brief flash of the wrong icon. The SVG method avoids all three issues, so reach for JavaScript only when you genuinely can’t ship an SVG.

You might also see the two-<link>-with-media pattern recommended. Skip it — the media attribute on <link rel="icon"> is unreliable across browsers, and most ignore it and just load the first icon. For the full rundown of which favicon tags and attributes are actually honoured, see the Favicon HTML Reference.

Browser support: don’t overstate it

Dark-mode SVG favicons work in Chrome, Edge, and Firefox — those render the SVG and evaluate the prefers-color-scheme query. Safari is the caveat: it does not render SVG favicons consistently, and it falls back to your favicon.ico or PNG. So your fallback icon has to be the safety net.

The rule for that fallback: make the raster version readable on both a light and a dark background. The simplest approach is a single high-contrast mark — for example, a coloured background tile with a light glyph — rather than a transparent-background icon that depends on the chrome colour. If you’d rather keep transparency, test it against both backgrounds before shipping; the transparent favicons guide covers when transparency helps and when a solid tile is safer.

One more limit worth stating plainly: the PWA manifest has no dark-mode mechanism. Home-screen and install icons can’t switch by theme. Design those to read on any background and let the SVG handle theme-switching in the browser tab only.

Summary

A dark-mode favicon is one file done right, not two files juggled by media attributes:

Continue reading:

Frequently asked questions

How do I make a favicon that changes in dark mode?

Use a single SVG favicon with an inline <style> block that contains @media (prefers-color-scheme: dark) and recolours the fill. The browser swaps colours automatically when the OS theme changes — one file, no JavaScript. Reference it with <link rel='icon' href='/favicon.svg' type='image/svg+xml'>.

Does the SVG dark-mode favicon work in Safari?

Not reliably. Chrome, Edge, and Firefox honour the prefers-color-scheme media query inside an SVG favicon; Safari does not render SVG favicons consistently and falls back to your favicon.ico or PNG. Make that fallback readable on both light and dark browser backgrounds.

Why does my favicon disappear in dark mode?

A dark logo on a transparent background vanishes against the dark browser chrome, and a white logo vanishes against light chrome. The fix is either an SVG that recolours itself with a media query, or a single high-contrast mark (like a coloured shape with a light glyph) that reads on both backgrounds.

Can I use two link tags with media attributes for a dark-mode favicon?

You can, but it is unreliable. The media attribute on <link rel='icon'> is poorly supported across browsers, so most browsers ignore it and load whichever icon comes first. A media query inside a single SVG, or a JavaScript swap, both work more consistently.

Can a PWA manifest icon adapt to dark mode?

No. The web app manifest has no prefers-color-scheme mechanism, so home-screen and PWA icons cannot switch by theme. Design one icon that reads on any background — see the PWA manifest guide — and let the SVG handle dark mode in browser tabs.

Related guides

← All guides