Favicon That Works for Light and Dark Mode
Table of Contents
Prefers Color Scheme
Majority of modern operating systems let the user choose between a light and dark mode preference (besides Linux as far as I know ๐ข).

We can take advantage of this by using the prefers-color-scheme media query to change the favicon based on the userโs preference.
@media (prefers-color-scheme: dark) {
/* ... */
}
If we look at caniuse the prefers-color-scheme
media query is supported across 91% of browsers.

Using JavaScript
The first method is using JavaScript to change the favicon based on the userโs preference using the matchMedia API that can listen for changes and return true
or false
if the media query matches.
// select the favicon ๐
const faviconEl = document.querySelector('link[rel="icon"]')
// watch for changes ๐ต๏ธ
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
mediaQuery.addEventListener('change', themeChange)
// listener ๐
function themeChange(event) {
if (event.matches) {
faviconEl.setAttribute('href', 'favicon-dark.png')
} else {
faviconEl.setAttribute('href', 'favicon-light.png')
}
}
Using the Media Attribute
Inside the external resource link element you can specify a media
attribute that accepts a media type such as print
and screen
, or a media query.
<link
href="favicon-light.png"
rel="icon"
media="(prefers-color-scheme: light)"
/>
<link
href="favicon-dark.png"
rel="icon"
media="(prefers-color-scheme: dark)"
/>
The media
attribute is supported across 97% of browsers.

Using a SVG Favicon
I prefer using a SVG favicon since itโs easy to change and you donโt have to think about the dimensions and size. Unfortunately, SVG favicons are only supported across 74% of browsers. We have to provide a fallback version for Internet Explorer and Safari.


<link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="icon" href="favicon.png" type="image/png">
Scalable Vector Graphics (SVG) are amazing because theyโre a self-contained Document Object Model (DOM) that lets you do anything inside it such as using a style
tag for CSS to take advantage of what we learned so far.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 134 134">
<style>
path {
fill: black;
}
@media (prefers-color-scheme: dark) {
path {
fill: white;
}
}
</style>
<path
d="M44.193 81.846c-10.615.683-20.248 4.726-25.714 19.13-.622 1.643-2.117 2.64-3.86 2.64-2.94 0-12.029-7.32-14.619-9.088.003 21.788 10.038 40.939 33.87 40.939 20.07 0 33.866-11.581 33.866-31.8 0-.823-.172-1.61-.257-2.416zM121.153 0c-4.011 0-7.771 1.775-10.64 4.352-54.083 48.313-59.71 49.448-59.71 63.67 0 3.625.86 7.08 2.31 10.24l16.885 14.07c1.908.476 3.874.801 5.924.801 16.433 0 25.958-12.03 55.87-67.855 1.952-3.796 3.677-7.898 3.677-12.168C135.47 5.461 128.59 0 121.153 0z"
/>
</svg>
If you want Prettier to format your SVG nicely temporarily rename it to use the *.html extension, or specify inside your editor to treat it as a HTML file. You can also use SVGOMG to optimize your SVG before โ which helps a lot to reduce the amount of markup inside caused by exporting it.
Conclusion
The only downside to this method is the browser theme set by the user, since they could be using light mode with a dark theme.
Thanks for reading! ๐โโ๏ธ
If you want to support the content you're reading or watching on YouTube consider becoming a patreon starting low as 1$ per month.
Become a patreonEvery post is a Markdown file so contributing is simple as following the link below and pressing the pencil icon inside GitHub to edit it.
Edit on GitHub