不能靠 window.matchmedia 自动切换 svg 图标集,需监听系统主题变化后由 js 主动操作 dom 或 css 变量实现响应式切换;svg 必须内联、移除内联颜色属性,统一用 css 变量控制,并配合 data-theme 属性与媒体查询实现主题适配。

不能靠 window.matchMedia 自动切换 SVG 图标集——它只负责监听系统主题变化,真正切换图标必须由 JavaScript 主动操作 DOM 或 CSS 变量。核心在于“监听 + 响应”,而不是“自动替换”。
准备两套 SVG 图标并统一内联写法
SVG 图标要响应主题,不能作为 <img src="..."> 引入,必须内联到 HTML 中(即把 SVG 代码直接写在页面里或通过 JS 插入),否则无法被 CSS 控制。
- 移除所有
fill、stroke等内联颜色属性(例如<path fill="#333"></path>),它们会锁死颜色,阻断主题响应 - 统一用 CSS 变量控制颜色:
svg path, svg circle { fill: var(--icon-color); stroke: var(--icon-stroke); } - 确保变量定义在
:root下,并用@media (prefers-color-scheme: dark)覆盖
用 matchMedia 监听系统主题并同步 data-theme
监听本身不复杂,但必须做两件事:读取初始状态 + 绑定 change 事件。漏掉任一环节都会导致首屏错位或后续无响应。
- 调用
const mql = window.matchMedia('(prefers-color-scheme: dark)')获取查询对象 - 立即执行
document.documentElement.setAttribute('data-theme', mql.matches ? 'dark' : 'light') - 再绑定监听:
mql.addEventListener('change', e => document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'light')) - 注意:不要用匿名函数,方便后续清理;单页应用中务必在卸载时调用
removeEventListener
配合 CSS 实现图标颜色自动更新
JS 只负责设置 data-theme 属性,样式交由 CSS 完成,解耦清晰、性能好、可维护性强。
-
:root中定义默认变量值(浅色模式):--icon-color: #333; --icon-stroke: #666; - 用媒体查询覆盖深色模式:
@media (prefers-color-scheme: dark) { :root { --icon-color: #f0f0f0; --icon-stroke: #aaa; } } - 再加一层
data-theme优先级(用于用户手动覆盖):html[data-theme="dark"] { --icon-color: #f0f0f0; } - 这样无论系统切换还是用户点开关,图标颜色都会即时更新,无需重绘或 JS 操作 SVG 元素
兼容 fallback 与 SSR 注意事项
服务端渲染(如 Next.js、Nuxt)中 window 不存在,直接调用 matchMedia 会报错;旧版 Safari 对 change 事件支持不稳定,需兜底。
- 加运行时守卫:
if (typeof window !== 'undefined') { /* matchMedia 相关逻辑 */ } - 不支持
prefers-color-scheme时,fallback 到 localStorage 记录的用户选择,或默认浅色 - 部分安卓 WebView 可能不触发
change,可加轻量定时器每 2 秒检查一次mql.matches(仅限必要场景) - 图标资源路径确保大小写敏感、部署后可访问(Linux 服务器区分 favicon-dark.svg 和 Favicon-Dark.svg)











