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/folder >}}
{{< /filetree/container >}} {{< /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. At minimum, include `favicon.svg` in your `static` folder. This will be used as the default favicon for your site.
Use tools like [favicon.io](https://favicon.io/) or [favycon](https://github.com/ruisaraiva19/favycon) to generate such icons.
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 ### 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 shortcut" href="{{ "favicon.ico" | relURL }}" sizes="32x32" />
<link rel="icon" href="{{ "favicon.svg" | relURL }}" type="image/svg+xml" /> <link rel="icon" href="{{ "favicon.svg" | relURL }}" type="image/svg+xml" id="favicon-svg" />
<link rel="icon" href="{{ "favicon-dark.svg" | relURL }}" type="image/svg+xml" media="(prefers-color-scheme: dark)" />
<link rel="icon" href="{{ "favicon-16x16.png" | relURL }}" type="image/png" sizes="16x16" /> <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="icon" href="{{ "favicon-32x32.png" | relURL }}" type="image/png" sizes="32x32" />
<link rel="apple-touch-icon" href="{{ "apple-touch-icon.png" | relURL }}" sizes="180x180" /> <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" -}} {{- $jsFileTree := resources.Get "js/filetree.js" -}}
{{- $jsSidebar := resources.Get "js/sidebar.js" -}} {{- $jsSidebar := resources.Get "js/sidebar.js" -}}
{{- $jsBackToTop := resources.Get "js/back-to-top.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 -}} {{- if hugo.IsProduction -}}
{{- $scripts = $scripts | minify | fingerprint -}} {{- $scripts = $scripts | minify | fingerprint -}}
{{- end -}} {{- end -}}