skip to content

A page's `<head>` declares several `<link rel="icon">` candidates with different `sizes` and `type` values. How does the browser decide which one to use, and where does an SVG favicon fit into that set?

level: middleimportance: nice to knowfreq 30%

answer

  1. candidates, not a last-one-wins cascade
  2. two attributes describe each file
  3. one file that never pixelates
  4. the keyword that means every size
  5. the fallback that is not universal

basics

~20 s

The browser treats the icon links as a candidate list and picks the one whose declared sizes and type best fit the surface it is drawing. An SVG icon is size-agnostic, so one file covers every density, with an ICO or PNG behind it as a fallback.

solid answer

~40 s

Multiple `<link rel="icon">` tags form a candidate set rather than an ordered override chain. Each candidate advertises itself with `type` — the MIME type, so a browser can skip a format it cannot decode without fetching it — and `sizes`, either concrete dimensions like `sizes="32x32"` or the keyword `sizes="any"` for a scalable format or a multi-image ICO. The browser then asks for the size it needs for that surface and takes the closest match. An SVG favicon (`type="image/svg+xml"`) collapses the whole raster ladder into one file, which is why the common recipe is a single SVG plus one ICO marked `sizes="any"` so the raster fallback is not preferred over the vector. Tie-breaking between equally good candidates is not identical across browsers, so keep the set small rather than relying on subtle ordering.

code

html · 2 lines
html
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="icon" href="/favicon.ico" sizes="any">

go deeper

for a junior

Know that you can declare more than one icon and that type names the file format while sizes names its dimensions.

for a middle

Be ready to explain that the links form a candidate set the browser selects from by size and format, and to write the two-line SVG-plus-ICO recipe from memory including why the ICO gets sizes="any".

for a senior

Expect a question about a blurry or wrong-looking icon on high-DPI screens — reason from what the candidates promise versus what the files really contain, rather than adding more tags.

for a principal

Frame it as asset-maintenance cost: one vector plus one fallback is a set the brand team can re-cut in minutes, while a generated ladder of platform-specific rasters silently rots after every redesign.

## A candidate set, not a cascade It is tempting to read a block of icon links like CSS — last one wins. That is the wrong model. Every `<link rel="icon">` in the document contributes a *candidate*, and each candidate carries a self-description. When the browser needs an icon it decides what size it wants for that surface (a 16 or 32 CSS-pixel tab icon at some device pixel ratio, a larger bookmark or task-switcher tile) and then selects from the set. ```html <link rel="icon" href="/icon-32.png" type="image/png" sizes="32x32"> <link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192"> ``` Here the browser drawing a tab will prefer the 32 asset and a surface wanting a large tile will prefer the 192 one — the order in the markup is not what decided it. ## What each attribute tells the browser **`type`** is the MIME type of the resource: `image/svg+xml`, `image/png`, `image/x-icon`. Its value is that it lets a browser rule a candidate out *before* downloading it. A browser that will not render SVG icons can discard the SVG candidate on the strength of the declared type and go straight to the raster fallback. **`sizes`** is a space-separated list of `WIDTHxHEIGHT` values in CSS pixels, or the single keyword `any`. `any` means "this resource works at any size" — the honest description of an SVG, and the pragmatic description of an ICO that packs several bitmaps. Neither attribute is validated against the file. They are promises. A `sizes="32x32"` that actually points at a 512-pixel PNG will still be chosen for the 32-pixel surface and then scaled, wasting the bytes. ## Why the SVG favicon changed the set Before vector icons the only way to look sharp on every display was to ship a ladder of PNGs — 16, 32, 48, 96, 180, 192, 512 — each with its own link. An SVG icon is resolution-independent by construction, so one file serves every surface and every device pixel ratio. The widely used recipe is two lines: ```html <link rel="icon" href="/favicon.svg" type="image/svg+xml"> <link rel="icon" href="/favicon.ico" sizes="any"> ``` The `sizes="any"` on the ICO is deliberate. Without a size hint on both candidates, a browser comparing a concretely sized raster against the vector can end up preferring the raster; declaring both as size-agnostic and letting `type` differentiate them is what makes the SVG win where it is supported and the ICO take over where it is not. Keep the ICO because SVG favicon support is not universal — some browsers and many non-browser consumers (feed readers, chat link unfurlers, crawlers) still expect a raster. ## Authoring the SVG itself Two practical constraints on the asset, both markup-adjacent: - **It is rendered tiny.** A logo with fine strokes or small text turns to mush at 16 pixels. Favicon SVGs are usually a simplified mark, not the full brand lockup. - **It can respond to the user's colour scheme.** An SVG favicon carries its own stylesheet, so a `prefers-color-scheme` rule inside the file can flip the mark's colour between light and dark browser chrome. That is one asset behaving two ways, which no PNG can do: ```html <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> <style> path { fill: #111; } @media (prefers-color-scheme: dark) { path { fill: #fff; } } </style> <path d="M4 4h24v24H4z"/> </svg> ``` Support for that trick varies by browser; treat it as an enhancement, and make sure the default colour is legible on both light and dark chrome. ## Practical guidance - Keep the candidate set to two or three entries. A long list is more surface for a stale asset to hide in and gains nothing once a vector covers the range. - Always declare `type` on the SVG candidate. It is the attribute that lets a non-supporting browser skip it cheaply. - Do not lie in `sizes`. The attribute is the only information the browser has before the fetch. - Do not rely on cross-browser tie-breaking. If two candidates are equally good descriptions of what the browser wants, which one it takes is not something to build on — remove the ambiguity instead. - Separate concerns: `rel="apple-touch-icon"` and the icons listed in a web app manifest are *different* surfaces with their own selection, not extra members of this candidate set.

  • If the SVG covers every size, why keep the ICO at all?
    SVG favicon support is not universal across browsers, and plenty of non-browser consumers — crawlers, feed readers, chat link previews — expect a raster at a predictable path. The ICO is a few kilobytes of insurance, and it doubles as the file behind the implicit `/favicon.ico` request for clients that never parsed your markup.
  • What actually goes wrong if `sizes` describes a file inaccurately?
    Nothing errors — the browser trusts the attribute. It picks the candidate on the strength of a false promise, then fetches an asset that is the wrong resolution for the surface and scales it, so you either get a blurry icon or you ship a 512-pixel PNG to draw a 16-pixel tab. The attribute is a hint the browser cannot verify before the fetch.
  • Can an SVG favicon change with the user's dark mode setting?
    Yes — the SVG file carries its own styles, so a `prefers-color-scheme` media query inside it can swap the mark's fill between light and dark browser chrome. Browser support for re-evaluating that in the favicon surface varies, so pick a default fill that stays legible either way and treat the swap as an enhancement.

saying these in an interview costs you the question

  • Says the last icon link in the head overrides the earlier ones
  • Thinks sizes and type are validated against the actual file
  • Believes you must still ship a full ladder of PNG sizes alongside an SVG
  • Claims every browser renders SVG favicons so the ICO is dead weight
  • Treats apple-touch-icon and manifest icons as more entries in the same candidate list

context