Dark Mode Favicons: Make One That Adapts
A dark navy mark vanishes against a dark tab strip. You can fix that from one SVG, or from two PNGs, but you still keep a default icon underneath.
What dark mode actually changes
The browser tab strip is light in light mode and dark in dark mode. Your favicon does not change with it unless you make it change. A mark that looks sharp on white can disappear on a near-black tab, and the reverse is true for a light mark on light chrome.
You have two ways to respond. Ship one SVG that recolours itself, or ship two PNGs and let the browser pick based on the OS setting. The SVG route is one file and one request. The PNG route works on more clients but its support for media-swapped favicons is uneven, so it leans on the fallback more often.
Method A: one SVG that flips itself
An SVG favicon can carry its own CSS. Put a prefers-color-scheme: dark media query inside the SVG and change the fill there. The browser reads the OS setting and repaints the icon with no second file and no extra link tag.
This is the method to reach for first. It is one file, it stays crisp at every size, and it is the only approach where a single asset covers both themes.
The SVG, with the fallbacks
<!-- In your <head>: SVG first, then the raster fallback -->
<link rel="icon" type="image/svg+xml" href="/icon.svg">
<link rel="icon" href="/favicon.ico" sizes="any">
<!-- icon.svg, with the theme rule baked in -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<style>
path { fill: #1a1a1a; }
@media (prefers-color-scheme: dark) {
path { fill: #f5f5f5; }
}
</style>
<path d="M6 6h20v20H6z" />
</svg>A browser that reads SVG uses the first line and honours the media query. Everything else falls back to favicon.ico.
Method B: two PNGs on media-scoped link tags
If you cannot use SVG, export two PNGs (say a dark-on-light version and a light-on-dark version) and hint each with a media attribute on its link tag. The browser loads the one that matches the current theme.
Support for this is patchy. Some browsers ignore the media attribute on icon links and just take the first one they understand. That is why the last line matters: a plain favicon.ico with no media condition is the default any client can fall back to.
The two-PNG setup
<link rel="icon" type="image/png" href="/favicon-dark.png"
media="(prefers-color-scheme: dark)">
<link rel="icon" type="image/png" href="/favicon-light.png"
media="(prefers-color-scheme: light)">
<link rel="icon" href="/favicon.ico" sizes="any">Keep the unconditional favicon.ico last so a browser that ignores the media hints still has an icon.
The lazy route that just works
If none of this is worth the effort, use one mid-tone mark. A colour with enough contrast to read on both light and dark chrome (a saturated brand colour, not near-black and not near-white) is legible in both themes from a single file.
This is the pragmatic default. You lose the perfect match to each theme, but you gain one asset that never disappears and no media conditions to get wrong.
Frequently asked questions
How do I make a favicon change for dark mode?
Use an SVG favicon with a prefers-color-scheme: dark media query inside its styles that swaps the fill colour, or ship two PNGs on media-scoped link tags. Keep a plain favicon.ico as the default either way.
Do dark mode favicons work in every browser?
SVG favicons with an internal media query are well supported on modern browsers. Media-swapped PNG favicons are less reliable, so always include an unconditional fallback icon.
Can I skip dark mode and use one favicon?
Yes. Pick a mid-tone mark with enough contrast to read on both light and dark tabs. It is one file and it never vanishes against either theme.
Does the favicon.ico need to change for dark mode?
No. The favicon.ico is your default fallback for older clients and crawlers. Leave it as a single legible version and handle theme swapping with the SVG or PNG links above it.