Website Favicon

It's quite easy to set a simple favicon for your website, but managing custom version for each platform and having a responsive icon is something rather unique that can be the cherry on top of a well-polished website. Let's see how I did it and how you can too.

Website Favicon

First things first, if you have Cloudflare enabled on your site be sure to enable the developer mode so you can see changes in real time without going through a CDN. I wanted a really simple favicon with my initials. No crammed logo, easily readable. I found a website that generate an SVG path from simple text and custom font: https://danmarshall.github.io/google-font-to-svg-path/

GitHub - danmarshall/google-font-to-svg-path: Create an SVG path from a Google font
Create an SVG path from a Google font. Contribute to danmarshall/google-font-to-svg-path development by creating an account on GitHub.

I chose Noto Serif for the font, easier to read on a small icon but you can use any font you like. I then downloaded the SVG file. Note that you can continue with any SVG file, I went this way simply because I wanted a text-only favicon.

Theme Responsive w/ CSS Magic

Next I made the SVG file theme-reactive: in a single file there is a normal version (light mode) with black text and a dark mode version with withe text. This is done automatically with CSS embedded in the SVG so that if the color scheme is dark the resulting image has it's colors inverted:

@media (prefers-color-scheme: light) { 
    :root { filter: none; } 
}
@media (prefers-color-scheme: dark) { 
    :root { filter: invert(100%); } 
}

After uploading the original SVG file to the following site I modified the Dark Icon starting from the regular one and choosing to invert colors. From the downloaded zip extract favicon.svg.

SVG Favicon Generator with dark mode support
Create the perfect SVG favicon: support dark mode, add contrast in seconds, see how it will look like in browser tabs and Google result pages

Square □

Since the favicon must be a square I modified the size of downloaded favicon.svg. Open the file in any text editor an change the lower dimension (height in my case) to match the bigger one. Then recenter the viewBox by translating it. So from this:

<… width="145.166" height="71.387"><svg width="145.166" height="71.387" viewBox="0 0 145.166 71.387" …

To having the same values for height and an adjusted viewBox to match the new y coordinate (-width/2):

<… width="145.166" height="145.166">< width="145.166" height="145.166" viewBox="0 -36.89 145.166 145.166" …

Here is the full SVG file currently hosted at fabricemonasterio.dev/favicon.svg:

Platform Dependent

Now that we have a dynamic and square favicon.svg we can proceed to create all the different version for various platforms such as classic Desktop, Google search result, iOS web clip, Android icon, macOS… I used this website that allows great customization:

Favicon Generator for perfect icons on all browsers
The ultimate favicon generator. Design your icons platform per platform and make them look great everywhere. Including in Google results pages.

I left the “Desktop Browsers and Google Result Pages” tab stock, on the “iOS - Web Clip” tab I added a solid white background, on the “Android Chrome” tab I applied a slight drop shadow and selected as theme color the accent used on the website, same for “Windows Metro” and “macOS Safari”. The “Favicon Generator Options” section deserves some special attention: I host the favicon files on the root of my domain, so the “Path” tab is unchanged. “Version/Refresh” is useful if you already had a favicon set and someone already visited your website, but for testing out by yourself I suggest doing the "fresh chrome" method described below. In “Additional files” I selected both options. Now generate the favicon package and download it. Extract the zip file in the root of the website and copy the favicon.svg that we uploaded to this last website (it's the square one containing the dynamic CSS code) too.

Using it

Change html code by using the correct file path in href (my file are served on the root of the domain while the blog is on a subdomain), then add the link to the theme-responsive favicon.svg generated before. Using Ghost as CMS I inserted it in the Site Header portion of the injected code (Ghost Settings > Code injection).

<link rel="apple-touch-icon" sizes="180x180" href="https://fabricemonasterio.dev/apple-touch-icon.png">
<link rel="icon" type="image/svg+xml" href="https://fabricemonasterio.dev/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="https://fabricemonasterio.dev/favicon-32x32.png">
⋮

You can check my full config viewing the source code of my site (copy link and paste in address bar) and searching for Favicon.

That's all! You should now have the perfect favicon for every platform.

CORS

While visiting your site you should check in the Console (available in the browser's Developer Tools) that no error such this one is reported: Access to manifest at 'https://fabricemonasterio.dev/site.webmanifest' from origin 'https://blog.fabricemonasterio.dev' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Add CORS header to the response given by the web server that serve the favicon files otherwise browsers will not load site.manifest due to CORS header 'Access-Control-Allow-Origin' missing. The same apply to all file hosted on the main domain but requested by a subdomain. Since I use træfik as reverse proxy I added the following middleware  named cors to the router that menages fabricemonasterio.dev:

 http:
  middlewares:
    cors:
      headers:
        accessControlAllowMethods:
          - GET
        accessControlAllowOriginList:
          # Allow loading of fabricemonasterio.dev/site.manifest (favicon)
          # by Ghost hosted on blog.fabricemonasterio.dev
          - 'https://blog.fabricemonasterio.dev'

Testing

To test with a fresh chrome browser (no cache, no extensions, no cookies…) you can use the following command. Toggle between dark mode and light mode with the chrome flag --force-dark-mode.

sh -c '\
HOME=$(mktemp -d); \
echo Home: $HOME; \
env HOME=$HOME google-chrome-stable \
--no-default-browser-check --no-first-run \
--force-dark-mode \
https://blog.fabricemonasterio.dev; \
rm -rf -- $HOME'
💡
You can start chrome browser with custom flags, for example forcing dark mode or launch an incognito windows.

Remember to disable Cloudflare Development Mode if you have enabled it before.  If a website linked here is down it's worth checking on the Wayback Machine, I archived them. It might not work though due to server-side processing.