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.
The Logo
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/
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
.
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:
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'
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.