How to Create a Favicon for Dark Mode?

Dark mode is getting wildly popular these days ever since Apple shipped it with Mojave. However, the usefulness of dark mode can be negated by websites that are predominantly white. That’s why Webkit introduced a media query attribute, prefers-color-scheme, to enable developers to apply styles specific to dark mode. As of April 2019, the support for it is still poor, but it’s on the roadmap for both Firefox and Chrome. The support percentage is bound to climb up once both these browsers start supporting it.

But prefers-color-scheme still won’t help you with the favicon, which can look very weird on dark-mode if your icon uses dark colors. For instance, this is how my Mac App’s favicon landing page looks on dark mode:

Let’s see how we can solve this problem.

Detecting Dark mode in Javascript

Unfortunately, there’s no direct API to detect dark mode on Javascript, but there’s a matchMedia API that you can use to check if a media query condition is satisfied.

if (window.matchMedia("(prefers-color-scheme: dark)")) {
    console.log ("dark mode is enabled");
}

matchMedia also supports the addListener method, which you can use to trigger changes when media query matches.

window.matchMedia("(prefers-color-scheme: dark)").addListener(function () {
    console.log ("changed to dark mode")
})

Changing Favicon when Dark Mode Detected

Once we have that detection mechanism in place, we can easily set a new favicon in dark mode. Let’s say I have a favicon image file favicon--dark.png then this is the code you’ll use.

function applyIcon (type) {
    var link = document.querySelector("link[rel*='icon']") || document.createElement('link');
    link.type = 'image/x-icon';
    link.rel = 'shortcut icon';

    if (type === "dark") {
        link.href = '/favicon--dark.png';
    } else {
        link.href = '/favicon.png';
    }

    document.getElementsByTagName('head')[0].appendChild(link);
}

var dmQuery = window.matchMedia("(prefers-color-scheme: dark)");
var lmQuery = window.matchMedia("(prefers-color-scheme: light)");

// Check on initial load if dark mode is already there. Apply the dark
// mode favicon if true.
if (dmQuery.matches) {
    applyIcon("dark");
}

dmQuery.addListener(function(){
    applyIcon("dark")
});

lmQuery.addListener(function(){
    applyIcon("light");
});

Though this is a handy trick, a better solution is to use a fill color that has a good contrast on both light and dark backgrounds. For instance, check how Apple.com does it. The icon is gray which looks great on both modes.

Subscribe

Enjoyed this post? Get an email notification when I publish.

comments powered by Disqus