Images
Favicons and app icons: the sizes and formats you actually need
Icon checklists online range from three files to forty, and most of the long ones are inherited from browsers that no longer matter. This article separates what the standards and vendor documentation actually require from folklore. It covers the small set of files worth shipping, how a browser picks among them, the internal layout of an ICO file, how transparency and dark mode change the result, and how to check what a real browser asked for. It is written for anyone who owns a site's head markup.
By the MaffeiTools team · Updated · 9 min read
How a browser picks an icon, and what it does when you declare none
The HTML Standard defines the icon keyword on a link element. When a page declares several, the browser must choose the most appropriate one using the type, media and sizes attributes. If several are equally appropriate, the last one in document order wins. If the chosen file turns out to be unusable, for example an unsupported format, the browser must try the next best candidate. That tie-break rule is why the order of your link elements can change which icon appears.
The sizes attribute counts raw pixels, not CSS pixels. An icon shown 16 CSS pixels wide on a display with two device pixels per CSS pixel needs 32 raw pixels to look sharp. The keyword any marks a scalable resource such as an SVG. Per the standard, sizes must not claim dimensions that the file does not actually contain.
If a page declares no icon at all, the standard says browsers may request /favicon.ico from the site root. May, not must, so treat the root file as a courtesy fallback rather than a contract. The same text says browsers are not required to refresh an icon when the declared list changes, which is the reason a corrected favicon can take a while to show up in a tab you already had open.
The short list of files worth shipping
A current site can cover every mainstream surface with a handful of files. Everything else on longer checklists is either a size an operating system will scale for you or a leftover from a browser generation that read proprietary tags.
- favicon.ico containing 16, 32 and 48 pixel images, referenced with rel="icon" and sizes="32x32", or left at the site root for the fallback request. Google Search accepts it, and clients that never learned SVG still expect it.
- icon.svg, referenced with rel="icon" type="image/svg+xml" sizes="any". One file that stays sharp at any density and can react to dark mode.
- apple-touch-icon.png at 180 by 180 pixels, referenced with rel="apple-touch-icon". This is what iOS uses for a home screen shortcut.
- A web app manifest, linked with rel="manifest", whose icons array lists PNGs at 192 by 192 and 512 by 512. Chromium's installability criteria require both sizes.
- A maskable variant of the 512 pixel icon, listed as a separate manifest entry with purpose "maskable", if you want installed Android and desktop apps to look native.
Worth knowing. Google Search shows one favicon per hostname, read from the home page. Its documentation lists BMP, GIF, ICO, PNG, JPEG, PPM and TIFF as supported formats, and SVG is not among them, so an SVG-only setup can leave search results without an icon. Googlebot-Image must also be allowed to fetch the file, so a robots.txt rule that blocks the icon path defeats it.
Inside favicon.ico: the directory, the entries and the PNG payloads
An ICO file is a small directory followed by image data. The directory header is six bytes: a reserved 16-bit zero, a 16-bit type (1 for icons) and a 16-bit image count. Each image then gets a 16-byte directory entry with width, height, palette count, a reserved byte, color planes, bits per pixel, the byte length of the image, and its offset from the start of the file. All multi-byte values are little-endian, and a width or height byte of 0 means 256, because 256 does not fit in one byte.
The image data behind each entry can be a full PNG file, which is what the encoder in this repository writes. The example below was produced by that encoder (lib/tools/image/encoders/ico.ts) from three synthetic PNGs, a 16, a 32 and a 48 pixel square, each with an inset blue square on a transparent border. The first payload begins exactly where entry 0 says: at offset 54, which is 6 header bytes plus 3 entries of 16 bytes.
png sizes 16x16:86B 32x32:114B 48x48:161B total bytes 415 ICONDIR 00 00 01 00 03 00 ENTRY 0 10 10 00 00 01 00 20 00 56 00 00 00 36 00 00 00 ENTRY 1 20 20 00 00 01 00 20 00 72 00 00 00 8c 00 00 00 ENTRY 2 30 30 00 00 01 00 20 00 a1 00 00 00 fe 00 00 00 entry 0: w=16 h=16 planes=1 bpp=32 size=86 offset=54 payload starts 89 50 4e 47 0d 0a 1a 0a entry 2: w=48 h=48 planes=1 bpp=32 size=161 offset=254 payload starts 89 50 4e 47 0d 0a 1a 0a 256 px entry, width and height bytes: 00 00
Worth knowing. Reading the bytes: 10 10 is 16 by 16 in hex, 01 00 is one color plane, 20 00 is 32 bits per pixel, 56 00 00 00 is 86 bytes of image data, and 36 00 00 00 is offset 54. The eight bytes 89 50 4e 47 0d 0a 1a 0a are the PNG signature, which is how you can confirm a payload really is PNG.
Why the classic set is 16, 32 and 48
The sizes come from where the icon is drawn. The traditional tab icon slot is 16 CSS pixels, so a 16 pixel image is sharp on a standard display and a 32 pixel image is what a two-times display needs, per the raw-pixel rule above. 48 pixels is the size Google's documentation uses as its reference point. Google's favicon documentation sets the floor at 8 by 8 pixels and recommends going above 48 by 48 so the icon looks good on its various surfaces, and it requires a square image.
Putting all three in one ICO lets the client choose the closest frame instead of scaling a single image up or down. The tools split this job unevenly. The PNG to ICO and JPG to ICO converters write one image per file, at 32 pixels by default with sizes from 16 to 256 selectable, and they letterbox a non-square source on transparent padding rather than stretching it. The favicon generator can write a multi-size ICO from whichever of its 16, 32, 48, 64, 128, 192 and 512 pixel options are checked, ignoring anything above 256 because the format cannot hold it.
Apple touch icons and manifest icons: selection rules and sizes
Apple's archived Safari Web Content Guide describes the touch icon rules. Place a PNG named apple-touch-icon.png in the site root, or point a link element with rel="apple-touch-icon" at another file. When several sizes are declared, the system uses the one most appropriate for the device. If none matches, the smallest icon larger than the recommended size is used, and if none is larger, the largest available. Apple's own example markup lists 180 by 180 for retina iPhones, 167 by 167 and 152 by 152 for iPads. That page is an archive, and it defers to the Human Interface Guidelines for current sizes, so a single 180 pixel file is a defensible default that Apple's selection rule will downscale.
Manifest icons are separate. Chromium's installability criteria, published on web.dev, require the manifest to include an icon of 192 pixels and one of 512 pixels, along with a name, a start URL and a display mode. The web app manifest specification adds that user agents may reshape icons to match the platform, for example by rounding corners or filling a color, and recommends preparing images so nothing important is lost when that happens. The image resizer produces exact pixel dimensions from a master file, and the favicon generator exports 192 and 512 directly; neither writes a manifest file, so the JSON is yours to write.
Maskable icons and the safe zone, with the arithmetic
A maskable icon tells the platform it may cut the image to any shape. The manifest specification defines the safe zone as a circle centered in the icon with a radius of two fifths, 40 percent, of the icon's width, or of the smaller side if the image is not square. The browser may make everything outside that circle transparent, and it must not make anything inside it transparent. The specification also says that if a maskable icon contains transparent pixels, the browser must composite it on a solid fill of its own choosing, and suggests designers avoid transparency entirely.
For a 512 pixel maskable icon the circle has a radius of 204.8 pixels, a diameter of 409.6, and the largest square that fits inside it is about 289.6 pixels on a side (204.8 times the square root of 2). Logos with wide wordmarks rarely survive that, which is the practical reason to list the maskable file as its own manifest entry instead of reusing the ordinary 512 icon: the ordinary icon can keep its normal padding, and the maskable one gets a full-bleed background with the mark inside the circle. The specification tells user agents not to use an icon outside its stated purpose, so the separate entries do not fight each other.
Transparency and dark mode: what changes and what does not
PNG payloads in an ICO carry an alpha channel (the entries above declare 32 bits per pixel), so a transparent favicon shows whatever the tab color happens to be. A dark glyph with no background is legible on a light tab and nearly invisible on a dark one. The fixes are a solid or contrasting background shape inside the icon, or an outline, or a dark mode variant. The favicon generator has a transparent-background option for image icons, which makes this easy to trigger by accident.
An SVG icon can carry its own stylesheet, including a prefers-color-scheme media query, so one file can switch colors with the operating system theme. web.dev's article on adaptive favicons documents the technique and states that, as of its writing, SVG favicons allowing inline media queries worked in Firefox and Chromium-based browsers. Treat that as a date-stamped statement and test in the browsers you care about, keeping the ICO as the baseline for everything that ignores it. The SVG to image tool renders an SVG to PNG at a chosen scale with a transparent or solid background, which is the quickest way to preview what a raster fallback looks like.
Home screen and install icons are different again: for touch icons, Apple's guide is silent on transparency, and for maskable icons the specification says the browser fills transparent pixels with a color it picks. In both cases an opaque, full-bleed square is the version whose result you control.
Checking what a browser actually requested
Declared and delivered are two different things. In a Chromium or Firefox network panel, filter by the icon path or by image requests, reload, and read the URL, status code and content type for each icon request. A 404 on /favicon.ico is common when a site declares its icon elsewhere, and harmless as long as the declared file resolves. In Chromium DevTools the Application panel's Manifest view lists every icon in the manifest and can preview how a mask would crop it. Remember the earlier caveat: browsers need not refresh icons, so test in a fresh profile or private window.
The favicon checker fetches a page, collects link elements that carry an icon relation, reads the manifest, and sends HEAD requests for at most eight distinct URLs, then reports which resolved and with what content type. Its coverage list is derived from the declared attributes: whether an ICO, an SVG, a 32 pixel icon, an Apple touch icon, and 192 and 512 pixel manifest icons are declared. It does not download the image bytes, verify the pixel dimensions, tell you which icon a given browser selected, or judge maskable safe zones, so it complements the DevTools check rather than replacing it. To inspect an existing ICO, the ICO to PNG converter loads it through the browser's image decoder and writes a single PNG, so you get the one frame the browser chooses, not every size in the file.
Sources
- HTML Standard: the icon link type, sizes attribute and /favicon.ico fallback
- W3C Web Application Manifest: purpose member and icon masks and safe zone
- Apple Safari Web Content Guide (archive): specifying a webpage icon for Web Clip
- web.dev: What does it take to be installable? (192 and 512 pixel manifest icons)
- Google Search Central: Define a favicon to show in search results