Fav for Craft CMS

Usage

What comes out of one image

FileWhat wants it
favicon.ico16, 32 and 48px in one file — browser tabs, bookmarks, crawlers, link unfurlers
favicon-16x16.png … favicon-96x96.pngModern browsers, which prefer a PNG when offered one
icon.svgCopied through when the source is an SVG, for high-density tab strips
apple-touch-icon.pngThe iOS home screen, at 180px, flattened onto your background colour
icon-192.png, icon-512.pngAndroid launchers, through the manifest
mstile-150x150.pngWindows pinned tiles
manifest.jsonThe two launcher icons and your two colours
browserconfig.xmlThe tile, and its colour

Only files that exist are linked to. If part of a set could not be built, the browser gets fewer icons rather than links that 404, because a browser caches a missing icon and stops asking.

Source images

A square PNG, 512×512 or larger, works best. A non-square image is contained rather than cropped.

An SVG source is rasterised and also copied through as icon.svg, but only on servers running Imagick. GD cannot rasterise vector artwork, and when it fails it produces a blank PNG rather than an error, so Fav refuses an SVG under GD and says so on the screen. Upload a PNG instead.

SVGs are sanitised before they are copied or rasterised. Scripts, event handlers and references to other files or URLs are removed, because the copy is served from your site's own domain.

Where the tags go

By default Fav adds them to every front-end HTML page, just before the first </head>. This works whether or not the template calls {{ head() }}.

A page whose head already links to an icon is left alone, so a hand-built head keeps working. Turn off skipPagesWithIcons to add Fav's tags anyway. They go in last, which is the copy the browser keeps.

Responses that are not HTML are never touched. That includes feed.rss.twig, sitemap.xml.twig and other templates whose extension sets a different content type.

Twig

To place the tags yourself:

{{ craft.fav.tags() }}

Calling it turns off the automatic injection for that page, so the tags never appear twice.

{{ craft.fav.tagList() }}                     {# the tags as a list, to place one at a time #}
{{ craft.fav.url('apple-touch-icon.png') }}   {# one file's URL, or null if it was not generated #}
{{ craft.fav.favicon().themeColor }}          {# the set itself, for its colours #}

Each takes an optional site ID. They default to the current site.

/favicon.ico

Browsers, crawlers and link unfurlers ask for /favicon.ico at the site root, whether or not a page links to one. Fav answers that request. Craft only sees it when there is no real file at that path, so a favicon.ico you put in the web root yourself still wins.

Where the files live

In web/fav/<site uid>/, served by the web server as ordinary static files. If the web root is not writable — a read-only deploy, a container — they go to storage/fav/ and are served through Craft instead. Nothing else changes.

The folder is named by site UID, not ID. IDs differ between environments, and a set of icons that followed a database sync to the wrong site would be very hard to spot.

Staying current

Fav records a fingerprint of everything that affects the pixels: the image, its size and modification date, the colours, the padding and the manifest settings. Saving a set only regenerates it when that fingerprint has changed, so saving an unrelated setting costs nothing.

Replacing the source image in the assets index regenerates every set built from it.

Console commands

php craft fav/favicons/generate            # every site, only what is out of date
php craft fav/favicons/generate default    # one site, by handle
php craft fav/favicons/generate --force    # rebuild regardless
php craft fav/favicons/status              # what each site has, and whether it is current
php craft fav/favicons/clear               # delete the generated files, keep the settings
php craft fav/favicons/clear default       # one site