You upload a perfect logo, toggle your OS into dark mode, and open your site — only to watch your bright orange brand mark glare back at you from a dark tab bar. A flat PNG favicon can't see your system theme. But an SVG favicon with a built-in prefers-color-scheme media query can.

This guide focuses on one specific technique: embedding a CSS media query directly inside your .svg file so a single file swaps colors automatically. It's a different path than swapping two <link> tags in HTML — and it's the cleanest one for most sites.

Prerequisites

Before you start, you need three things:

If you don't have an SVG yet, export one from your design tool, or use Mzu favicondl to grab a clean vector from any image.

Step-by-Step: Add a Media Query Inside Your SVG Favicon

Step 1: Open your SVG file in a text editor

SVG is just XML. Right-click any .svg file and choose Open with → TextEdit or VS Code. You'll see something like:

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'>
  <rect width='64' height='64' rx='12' fill='#ff7a00'/>
  <path d='M20 22 L32 44 L44 22' stroke='#fff' stroke-width='6' fill='none'/>
</svg>

Step 2: Add a <style> block with the media query

Insert a <style> element right after the opening <svg> tag. Inside it, define your light-theme colors and override them for dark mode using prefers-color-scheme: dark:

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'>
  <style>
    .bg { fill: #ff7a00; }
    .stroke { stroke: #ffffff; }
    @media (prefers-color-scheme: dark) {
      .bg { fill: #1a1a1a; }
      .stroke { stroke: #ffb347; }
    }
  </style>
  <rect class='bg' width='64' height='64' rx='12'/>
  <path class='stroke' d='M20 22 L32 44 L44 22' stroke-width='6' fill='none'/>
</svg>

The browser re-evaluates prefers-color-scheme every time your OS theme changes. Your favicon updates without a reload in most modern browsers.

Step 3: Link it in your HTML <head>

Per the WHATWG HTML living standard, the rel='icon' link type supports SVG when you declare the correct MIME type with type='image/svg+xml':

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

Place this above any PNG or ICO fallback. See our favicon HTML cheat sheet for the full modern stack including Apple Touch and web manifest entries.

Step 4: Provide a raster fallback

Not every browser parses CSS inside favicons — most notably older Safari versions and some embedded web views. Ship a 32×32 PNG (or a multi-size ICO) for those clients:

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

Browsers use the first match, so SVG wins where supported.

Step 5: Test in both color schemes

Force a hard refresh (Ctrl/Cmd + Shift + R) and toggle your OS theme. In Chrome, Edge, and Firefox, the tab icon should switch live. If nothing happens, jump to the pitfalls below.

Common Pitfalls

Pitfall 1: Forgetting the viewBox

Without a viewBox, the SVG renders at its intrinsic size, which can be huge or zero. Always declare one: viewBox='0 0 64 64'.

Pitfall 2: Inline fill attributes override your CSS

If your shapes already carry fill='#ff7a00' as an attribute, your CSS class will lose the specificity battle. Move the color into a class, or delete the inline attribute entirely.

Pitfall 3: Aggressive favicon caching

Browsers cache favicons harder than almost any other file. After editing your SVG, append a query string during testing: /favicon.svg?v=2. Our cache-busting guide covers production strategies.

Pitfall 4: Safari pinned tabs ignore media queries

Safari's pinned-tab feature uses a separate monochrome safari-pinned-tab.svg. Media queries inside that file have no effect. Design it as a single-color silhouette and skip the <style> block.

Pitfall 5: Dark mode is not 'invert the colors'

Pick a dark-mode palette with real contrast against the browser's actual tab background (often #2b2a33 in Chrome, near-black in Safari). Running your icon through a contrast checker once saves support tickets later.

Wrapping up

The SVG media query approach gives you one source of truth: one file, two themes, zero JavaScript. It's the right default for any modern site that already has an SVG logo, and it works alongside — not against — the PNG and ICO fallbacks you should still ship for older browsers.

Check the documented requirements

The HTML Standard defines rel='icon' as the link relationship for an icon representing the current page.