The three rules of asking questions | Menu | Try before you buy

A favicon by itself is not a website

But what if it was?

Browsers will try a lot before they give up on rendering a website, this includes accepting binary garbage. Anything they don't know what to do with is just dumped on the screen as text.

Icon format

In the beginning, web icons used to be in Windows® icon format. This format was introduced with the very first version of the operating system, it still is the de facto icon type for modern Windows, and it has not actually significantly changed over all the years. The additions were increasing color capabilities, and the support to embed PNG files.

Fun fact: This is also the format used for static cursors on Windows

Web browsers

Web browsers will try to load the icon from /favicon.ico whenever you visit a web site. This can be changed using a meta tag

<link rel="shortcut icon" href="/custom/path/to/icon.png" />

The "shortcut" exists purely for backwards compatibility reasons, just using "icon" is sufficient now

Modern browsers allow you to use practically any type of supported image as an icon, including vector graphic formats like SVG.

Combining HTML with an image

Most image parsers don't have a problem if there's arbitrary data after the image content, so we could just stick the image and html together. This however is fairly unstable, and editing the image will destroy the HTML.

It would be better to use a supported mechanism, and for this, PNG is ideal.

A PNG has the following structure:

  1. Bytes (in hex): 89 50 4E 47 0D 0A 1A 0A
  2. IHDR chunk
  3. Any number of other chunks (at least one IDAT)
  4. IEND chunk

PNG Header byte sequence

The bytes are a fairly clever choice made by the authors:

  1. 89: If this is 09 we know that the topmost bit got shaved off due to a faulty 7-bit transmission somewhere. This is no longer relevant today
  2. 50 4E 47: The letters PNG
  3. 0D 0A: A standard internet linebreak. Used to detect if faulty CRLF to LF conversion happened somewhere, for example in FTP transmissions that wrongly use ASCII mode rather than binary mode
  4. 1A: (Known as CTRL+Z) used to terminate any attempt to print it to the terminal. On Windows, if you do type <pngfile> in the terminal, it will just print ëPNG and then end output rather than spewing binary onto the console.
  5. 0A: Same reason as 0D 0A but to detect faulty conversion into the other direction.

Chunks

Every PNG chunk has the exact same structure:

  1. 4 bytes: Length of the header payload
  2. 4 bytes: Name of the header
  3. variable: Payload
  4. 4 bytes: Checksum of the header

PNG values are big endian

Apart from that, there's very few rules for PNG files. The remaining rules mostly boil down to what chunks are mutually exclusive with each other, and what chunks require a certain ordering. For ordering, the rule mostly is "do not require backtracking", which for example means that headers that influence rendering must come before the raw pixel data.

The casing of the 4 character chunk name actually tells you a few bits about it:

  1. Critical chunk. If this is uppercase, and the decoder doesn't knows it, it must abort rendering
  2. Public chunk: If this is uppercase, the chunk is officially described in the PNG spec
  3. Reserved: This must always be uppercase
  4. Copy safe: If this is uppercase, it's safe for a PNG editor to just copy the chunk to the new file if they don't know how to deal with it.

Example: tEXT can be safely ignored, is officially described, and is safe to just copy.

Text chunk

The text chunk of a PNG is uncompressed. We use this to store our HTML code inside. As long as we tell the browser that this PNG is in reality of text/html type, it will happily render the HTML. There will be garbage data before and after the HTML, but this can be taken care off completely passively without any JavaScript.

If you want to read more about this on a website that is actually just a favicon, see here