DEV Community

Cover image for How to create favicons for darkmode (English) 🌚
Jolution
Jolution

Posted on • Edited on

How to create favicons for darkmode (English) 🌚

This article is also available in German πŸ‡©πŸ‡ͺ

Motives

πŸ‘‹πŸΌ Hello World,

my name is Julian. I'm a web developer, and I'm currently working more and more with darkmode.

The topic is about the adaptation of favicons.
Since I work a lot with WordPress, the integration is also thematized.

Requirement

Since Firefox version 41 (2015) and Chrome version 80 (2019), we can use SVG favicons.
However, there is no support in Safari yet.

For requirements, see Caniuse.com's browser support on the following topics:

  1. SVG favicons in the browser
  2. CSS Media Querie prefers-color-scheme

Caniuse: https://caniuse.com/?search=SVG%20favicons

Create basics

As source file I have my developer logo as SVG for maximum scalability and optimal performance.

Otherwise, an image (PNG, JPG) with the size of 260x260 pixels for best results.

From this we now export the following five formats and sizes:

Filename Size
favicon.ico 32Γ—32
favicon.svg -
apple-touch-icon.png 180Γ—180
icon-192.png 192x192
icon-512.png 512x512

I generate most of the files via the online service RealFaviconGenerator. I have left settings for this on the default.

But of course you can use other graphic programs and export the formats like .ico with the help of extensions.
If an icon does not come along or needs to be readjusted, you can of course export it separately as a file from Illustrator.
If you have Inkscape at hand, you can also just generate it directly from the Console.:

inkscape ./icon.svg --export-width=512 --export-filename="./icon-512.png"
Enter fullscreen mode Exit fullscreen mode

Now the following files should be available, which we load (e.g. via sFTP) into the document root of the page:

β”‚   └── public
|       β”œβ”€β”€ favicon.ico
|       β”œβ”€β”€ favicon.svg
|       β”œβ”€β”€ apple-touch-icon.png
|       β”œβ”€β”€ icon-192.png
|       β”œβ”€β”€ icon-512.png

|       β”œβ”€β”€ manifest.webmanifest    (see next paragraph)
|       β”œβ”€β”€ favicon_admin.svg       (optional: see next paragraph)
Enter fullscreen mode Exit fullscreen mode

The specification sizes="any" is currently important, because in Chrome instead of the svg the ico file is dragged.

Integration

Path

The documentroot is suitable as the storage path for the icons.

This has the advantage that favicon.ico can also be used, even if no HTML is used: Example for this, would be files, like a PDF file that is opened in the browser, or images.
If this is not possible, you could provide a redirect.

Files

Manifest file to upload:

Filename: manifest.webmanifest

{
    "name": "Jolution",
    "short_name": "Jolution",
    "icons": [
        { "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
        { "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" }
    ],
    "theme_color": "#292c2f",
    "background_color": "#292c2f",
    "display": "standalone"
}
Enter fullscreen mode Exit fullscreen mode

Alternative with the minimum specifications:

{
    "icons": [
        { "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
        { "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" }
    ]
}
Enter fullscreen mode Exit fullscreen mode

WordPress

// favicon frontend
add_action('wp_head', 'custom_favicon');
function custom_favicon() {
    echo '<link rel="icon" href="/favicon.ico" sizes="any">';
    echo '<link rel="icon" href="/favicon.svg" type="image/svg+xml">';
    echo '<link rel="apple-touch-icon" href="/apple-touch-icon.png">';
    echo '<link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials">';
    echo '<meta name="theme-color" content="#22343b" media="(prefers-color-scheme: light)">';
    echo '<meta name="theme-color" content="#fff" media="(prefers-color-scheme: dark)">';
}
Enter fullscreen mode Exit fullscreen mode

Alternatively, we can make it a line here or concatenate (concatenation):

add_action('wp_head', 'custom_favicon');
function custom_favicon() {
    echo '<link rel="icon" href="/favicon.ico" sizes="any"><link rel="icon" href="/favicon.svg" type="image/svg+xml"><link rel="apple-touch-icon" href="/apple-touch-icon.png"><link rel="manifest" href="/manifest.webmanifest"><meta name="theme-color" content="#22343b" media="(prefers-color-scheme: light)"><meta name="theme-color" content="#fff" media="(prefers-color-scheme: dark)">';
}
Enter fullscreen mode Exit fullscreen mode

Optional: Admin Favicon

As a little goodie to make it easier to differentiate between frontend and backend tabs in Chrome, i have a separate favicon located in the theme.

// favicon backend
add_action('login_head', 'custom_favicon_admin');
add_action('admin_head', 'custom_favicon_admin');
function custom_favicon_admin() {
    printf('<link rel="icon" href="%s/favicon_admin.svg" type="image/svg+xml">', get_stylesheet_directory_uri());
    echo '<meta name="theme-color" content="#22343b" media="(prefers-color-scheme: light)">';
    echo '<meta name="theme-color" content="#fff" media="(prefers-color-scheme: dark)">';
}
Enter fullscreen mode Exit fullscreen mode

If you don't have write-access to the document root and need to put the files in the theme, then you can use the printf statement above instead of echo.

If you also have the admin-icon in the document root, then you don't need get_stylesheet_directory_uri() and can work directly with /favicon_admin.svg:

echo '<link rel="icon" href="/favicon_admin.svg" type="image/svg+xml">';
Enter fullscreen mode Exit fullscreen mode

Fun: Emoji Favicon

If you like emojis, you can alternatively work with these, see the tweet by LeaVerou,
and the online services for this, emojicon.dev and fav.farm.

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><text x='0' y='14'>🌢</text></svg>
Enter fullscreen mode Exit fullscreen mode

Typo3

Important: Before including the following code, check that the number (=position) 20 is not already assigned and will thus be overwritten.

If there is already position 20 in your TypoScript, then it is best to check in increments of 10 if 10 or 30 is free.

headerData {
    20 = TEXT
    20 {
        value (
            <link rel="icon" href="/favicon.ico" sizes="any">
            <link rel="icon" href="/favicon.svg" type="image/svg+xml">
            <link rel="apple-touch-icon" href="/apple-touch-icon.png">
            <link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials">
            <meta name="theme-color" content="#22343b" media="(prefers-color-scheme: light)">
            <meta name="theme-color" content="#fff" media="(prefers-color-scheme: dark)">
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

Currently, the alternative embedding option shortcutIcon allows only one icon:

page.shortcutIcon = fileadmin/Icons/favicon.ico
Enter fullscreen mode Exit fullscreen mode

The meta information theme-color in the upper part, can not (currently) be included via page.meta, because no media query can be integrated here.

Static

In the head of the web page we put the following HTML code:

<head>

  <link rel="icon" href="/favicon.ico" sizes="any">
  <link rel="icon" href="/favicon.svg" type="image/svg+xml">
  <link rel="apple-touch-icon" href="/apple-touch-icon.png">
  <link rel="manifest" href="/manifest.webmanifest">

  <title>Example</title>
</head>
Enter fullscreen mode Exit fullscreen mode

Optionally, the theme-color can also be included above the title:

<meta name="theme-color" content="#22343b" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#fff" media="(prefers-color-scheme: dark)">
Enter fullscreen mode Exit fullscreen mode

Instead of content="#fff", CSS-variables can also be used here.
The variables in this example are from TailwindCSS.

echo '<meta name="theme-color" content="var(--teal-800)" media="(prefers-color-scheme: light)">';
echo '<meta name="theme-color" content="var(--white)" media="(prefers-color-scheme: dark)">';
Enter fullscreen mode Exit fullscreen mode

Darkmode

Since SVG is now well-supported by the major browsers, I'll focus only on the SVG file.

With a text program we open it and look at it.
An SVG file can get very large depending on the logo.
You could try to reduce this already in the vector program.
Additionally, you can compress the file with SVGOMG or other tools for Optimizing SVG.

Important: Make a backup of the original file before.

My developer logo is a J in a circle.
I exported this as one path, but this is of course not a must. Of course, multiple paths can be addressed.
I have assigned a dark color to the path by default.
If the darkmode is detected, the same path is defined with a white color.

Expected result:

Darkmode: β’Ώ

Lightmode: πŸ…™

<svg version="1.1" baseProfile="full" width="400" height="400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">
<path d="M200 0A200 200 0 0 0 0 200a200 200 0 0 0 200 200 200 200 0 0 0 200-200 200 200 0 0 0-76.736-157.21l-.028 156.01c0 4.268-.214 8.484-.636 12.64-.422 4.155-1.05 8.25-1.873 12.273-.824 4.023-1.843 7.975-3.047 11.846-1.204 3.87-2.593 7.66-4.157 11.356-1.563 3.697-3.302 7.302-5.205 10.805-1.903 3.504-3.97 6.904-6.19 10.192-2.222 3.288-4.6 6.463-7.118 9.516-2.52 3.052-5.18 5.98-7.977 8.777-2.796 2.796-5.727 5.46-8.78 7.98-3.052 2.518-6.227 4.892-9.515 7.114-3.288 2.22-6.688 4.29-10.19 6.192-3.504 1.903-7.11 3.642-10.806 5.205-3.697 1.564-7.487 2.953-11.357 4.157-3.87 1.203-7.823 2.22-11.846 3.044-4.024.824-8.12 1.45-12.274 1.873-4.156.423-8.372.64-12.64.64-3.914-.005-7.81-.195-11.677-.566-3.867-.372-7.703-.924-11.497-1.653-3.794-.727-7.545-1.633-11.242-2.71-3.696-1.076-7.34-2.324-10.917-3.74-3.577-1.415-7.088-2.997-10.52-4.742-3.435-1.744-6.79-3.65-10.054-5.715-3.267-2.064-6.443-4.285-9.517-6.66s-6.046-4.903-8.904-7.578l28.102-38.64s1.317 1.547 3.84 3.868c1.262 1.16 2.824 2.516 4.676 3.967 1.852 1.452 3.993 3 6.408 4.55 2.415 1.548 5.104 3.096 8.055 4.548 2.952 1.452 6.164 2.808 9.624 3.97 3.46 1.163 7.167 2.133 11.11 2.813 1.97.34 4 .61 6.087.792 2.088.183 4.23.28 6.43.283 2.636 0 5.24-.128 7.81-.38 2.568-.25 5.097-.622 7.583-1.112 2.487-.49 4.93-1.095 7.323-1.812 2.392-.716 4.732-1.545 7.017-2.478 2.285-.933 4.513-1.97 6.678-3.11 2.166-1.137 4.268-2.375 6.3-3.706 2.032-1.332 3.994-2.758 5.88-4.272 1.887-1.513 3.698-3.113 5.427-4.797 1.728-1.684 3.372-3.452 4.93-5.295 1.556-1.843 3.025-3.76 4.398-5.752 1.372-1.99 2.65-4.052 3.826-6.18 1.177-2.126 2.25-4.318 3.218-6.57.966-2.25 1.824-4.562 2.568-6.927.744-2.365 1.374-4.785 1.883-7.252.508-2.466.896-4.983 1.157-7.54.26-2.558.395-5.156.395-7.793l.015-147.084-.045-38.035A200 200 0 0 0 200 0z">
</path>
<style>
    path {
        fill: #22343b
    }
    @media (prefers-color-scheme: dark) {
        path{
            fill: #fff
        }
    }
</style>
</svg>
Enter fullscreen mode Exit fullscreen mode

Alternatively, instead of changing the color, you can also change the brightness.
Depending on the effort (amount of path adjustments) this can also be a solution.
Personally, however, I prefer the simple color adjustment.

@media (prefers-color-scheme: dark) {
  :root {
    filter: brightness(4);
  }
}
Enter fullscreen mode Exit fullscreen mode

https://codepen.io/jolution/pen/bGadeQY

If you now want to add as meta theme-color, this is also easily doable:

Fallback

Safari

Safari unfortunately does not yet support the automatically detectable darkmode.
The normal toggle functions would of course be no problem here.
When I have found a solution, I will of course update the article.

<link rel="mask-icon" href="favicon.svg" color="#22343b">
Enter fullscreen mode Exit fullscreen mode

Feel free to write me in the comments if you have a good and easy approach to this.

Other browsers

Since not all browsers support the media query features in the link tag, this polyfill fixes that.
However, JS is used here, so I would weigh the use and if in doubt, do without it.

You can use the favicon checker from realfavicongenerator to check the usage afterwards.
If a browser is missing for your taste, add the meta information from the generator and load the appropriate files.

Future Prospects

Manifest color definition

For some cases it would be ideal to already specify colors for both modes in the manifest.
If you are already interested in this, you can find further information as well as the exchange at github in English.

PWA / Maskable Icons

At web.dev there is a 2019 approach to the topic of PWA on the topic of "maskable icons".

Credits

Thanks to Andrey Sitnik (author of PostCSS and Autoprefixer) who gathered the above measurements as optimal set.
And also to Houssein Djirdeh (Software Engineer at @GoogleChrome) who also uses these specifications with 512x512.

Good luck and have fun with the implementation.

Top comments (0)