fix(favicon): dynamic favicon switching based on color scheme in js (#735)

* fix(favicon): dynamic favicon switching based on color scheme in js

* refactor(favicon): simplify favicon logic and ensure dynamic switching based on color scheme

* docs(favicon): enhance favicon setup instructions with dark mode support and adaptive SVG guidance
This commit is contained in:
Xin
2025-08-10 23:04:19 +08:00
committed by GitHub
parent 7ac1d59e9f
commit 096f0d9c22
5 changed files with 44 additions and 6 deletions

22
assets/js/favicon.js Normal file
View File

@@ -0,0 +1,22 @@
// {{ $faviconDarkExists := fileExists (path.Join "static" "favicon-dark.svg") }}
(function () {
const faviconEl = document.getElementById("favicon-svg");
const faviconDarkExists = "{{ $faviconDarkExists }}" === "true";
if (faviconEl && faviconDarkExists) {
const lightFavicon = '{{ "favicon.svg" | relURL }}';
const darkFavicon = '{{ "favicon-dark.svg" | relURL }}';
const darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)");
function updateFavicon(e) {
faviconEl.href = e.matches ? darkFavicon : lightFavicon;
}
// Set favicon on load
updateFavicon(darkModeQuery);
// Listen for system preference changes
darkModeQuery.addEventListener("change", updateFavicon);
}
})();

View File

@@ -188,10 +188,26 @@ To customize the [favicon](https://en.wikipedia.org/wiki/Favicon) for your site,
{{< /filetree/folder >}}
{{< /filetree/container >}}
Include `favicon.ico`, `favicon.svg` and `favicon-dark.svg` files in your project to ensure your site's favicons display correctly.
#### Basic Setup
While `favicon.ico` is generally for older browsers, `favicon.svg` and `favicon-dark.svg` are supported by modern browsers.
Use tools like [favicon.io](https://favicon.io/) or [favycon](https://github.com/ruisaraiva19/favycon) to generate such icons.
At minimum, include `favicon.svg` in your `static` folder. This will be used as the default favicon for your site.
You can create an adaptive SVG favicon that responds to system theme preferences by using CSS media queries within the SVG itself, following the approach described in [Building an Adaptive Favicon](https://web.dev/articles/building/an-adaptive-favicon).
#### Dark Mode Support
For enhanced dark mode support, add `favicon-dark.svg` to your `static` folder alongside `favicon.svg`. When both files are present, Hextra will automatically:
- Use `favicon.svg` for light mode or when no theme preference is detected
- Switch to `favicon-dark.svg` when the user's system is set to dark mode
- Respect the system's `prefers-color-scheme` setting for automatic switching
The dark mode favicon switching works across all modern browsers, including Firefox, and provides a seamless experience that matches your site's theme.
#### Additional Formats
While `favicon.ico` is generally for older browsers, modern browsers support SVG favicons which are preferred for their scalability and small file size.
Use tools like [favicon.io](https://favicon.io/) or [favycon](https://github.com/ruisaraiva19/favycon) to generate additional favicon formats if needed.
### Theme Configuration

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,6 +1,5 @@
<link rel="icon shortcut" href="{{ "favicon.ico" | relURL }}" sizes="32x32" />
<link rel="icon" href="{{ "favicon.svg" | relURL }}" type="image/svg+xml" />
<link rel="icon" href="{{ "favicon-dark.svg" | relURL }}" type="image/svg+xml" media="(prefers-color-scheme: dark)" />
<link rel="icon" href="{{ "favicon.svg" | relURL }}" type="image/svg+xml" id="favicon-svg" />
<link rel="icon" href="{{ "favicon-16x16.png" | relURL }}" type="image/png" sizes="16x16" />
<link rel="icon" href="{{ "favicon-32x32.png" | relURL }}" type="image/png" sizes="32x32" />
<link rel="apple-touch-icon" href="{{ "apple-touch-icon.png" | relURL }}" sizes="180x180" />

View File

@@ -7,8 +7,9 @@
{{- $jsFileTree := resources.Get "js/filetree.js" -}}
{{- $jsSidebar := resources.Get "js/sidebar.js" -}}
{{- $jsBackToTop := resources.Get "js/back-to-top.js" -}}
{{- $jsFavicon := resources.Get "js/favicon.js" | resources.ExecuteAsTemplate "favicon.js" . -}}
{{- $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang $jsNavMenu $jsFileTree $jsSidebar $jsBackToTop | resources.Concat "js/main.js" -}}
{{- $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang $jsNavMenu $jsFileTree $jsSidebar $jsBackToTop $jsFavicon | resources.Concat "js/main.js" -}}
{{- if hugo.IsProduction -}}
{{- $scripts = $scripts | minify | fingerprint -}}
{{- end -}}