A client's site launched with a beautiful black logo. Looked great on the white header. Then I opened it at night with dark mode on — the favicon was completely invisible against the dark browser tab. Nobody had thought to test it. Here's how I fix this now for every project.
Chrome, Firefox, and Safari all support system-level dark mode. When a user switches to dark mode, their browser tabs go dark too. If your favicon is a dark logo on a transparent background, it disappears. If it's a light logo, it disappears in light mode. You need both.
The cleanest approach — one SVG file that adapts automatically. Per MDN's prefers-color-scheme docs, SVG supports CSS media queries internally:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<style>
.light { display: block; }
.dark { display: none; }
@media (prefers-color-scheme: dark) {
.light { display: none; }
.dark { display: block; }
}
</style>
<rect class="light" fill="#111" .../>
<rect class="dark" fill="#fff" .../>
</svg>
Then reference it directly: <link rel="icon" href="/favicon.svg" type="image/svg+xml">. The browser handles the switching. I use this for all new projects where SVG favicons are acceptable.
For sites that need PNG fallbacks, declare two favicons with media queries in the <link> tag:
<link rel="icon" href="/favicon-light.png" media="(prefers-color-scheme: light)"> <link rel="icon" href="/favicon-dark.png" media="(prefers-color-scheme: dark)">
Generate both at GenFavicon — use a white background for light mode, a dark background for dark mode. Two downloads, two lines of HTML.
The lazy solution that works 80% of the time: add a 1-2px contrasting outline to your favicon. A white logo with a thin black stroke is visible on both light and dark backgrounds. It's not perfect — the outline looks slightly harsh on small sizes — but it prevents the "invisible favicon" problem without any extra code.
For client sites in 2026, I default to the SVG approach. Browser support for SVG favicons is at 91% (CanIUse). For the remaining 9%, I add a single 32×32 PNG with a contrasting outline as fallback. Two files, three lines of HTML, works everywhere.