📊写在前面
在网页设计中,跟随系统主题切换可以通过CSS和JavaScript实现。可以通过定义两套CSS变量,根据系统主题的颜色来切换变量的生效,从而实现不同主题下的页面样式变化。
例如,可以使用媒体查询API来获取系统主题的颜色,并根据匹配结果来适配页面的自定义属性。同时,可以注册媒体查询的change事件,当系统主题变化时重新调用函数,实现跟随系统的效果。
🖼️API简介
Window 的 matchMedia() 方法返回一个新的 MediaQueryList 对象,表示指定的媒体查询字符串解析后的结果。返回的 MediaQueryList 可被用于判定 Document 是否匹配媒体查询,或者监控一个 document 来判定它匹配了或者停止匹配了此媒体查询。
🚀实际效果
📚实例代码(HTML版)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>JS媒体查询之matchMedia API 实现跟随系统主题色切换效果</title><style>:root {--text-color: #333;--bg-color: #fff;}html[data-theme="dark"] {--text-color: #fff;--bg-color: #333;}html[data-theme="ligth"] {--text-color: #333;--bg-color: #fff;}html[data-theme="red"] {--text-color: #fff;--bg-color: #ff0064;}html[data-theme="green"] {--text-color: #fff;--bg-color: #67c23a;}html[data-theme="blue"] {--text-color: #fff;--bg-color: #0091db;}body {background-color: var(--bg-color);color: var(--text-color);}h1 {color: var(--text-color);text-align: center;}select {display: block;margin: 20px auto;font-size: 32px;}</style>
</head><body><h1>JS媒体查询之matchMedia API 实现跟随系统主题色切换效果</h1><hr><select name="theme" id="theme"><option value="ligth">亮色</option><option value="dark">暗色</option><option value="os">系统跟随</option><option value="red">红色</option><option value="green">绿色</option><option value="blue">蓝色</option></select><script>const theme = document.getElementById('theme');// 获取系统主题const metch = window.matchMedia('(prefers-color-scheme: dark)');// 设置主题const setTheme = (theme = '') => {document.documentElement.setAttribute('data-theme', theme ? theme : metch.matches ? 'dark' : 'ligth');};// 监听主题切换theme.addEventListener('change', (e) => {if ('os' === e.target.value) {setTheme();// 监听系统主题切换metch.addEventListener('change', setTheme);} else {setTheme(e.target.value);metch.removeEventListener('change', setTheme);}});</script>
</body></html>
📚实例代码(Vue3.js + TS版)
hook.ts
import { ref, watchEffect } from 'vue';// 定义主题类型
type Theme = 'light' | 'dark' | 'os';// 存储主题的key
const STORE_KEY = '__hteme__';// 获取存储主题
const theme = ref<Theme>(localStorage.getItem(STORE_KEY) as Theme || 'light');// 获取系统主题
const media = globalThis.matchMedia('(prefers-color-scheme: dark)');// 监听系统主题变化
const listener = () => {document.documentElement.dataset.theme = media.matches ? 'dark' : 'light';
}// 监听theme变量值变化
watchEffect(() => {// 更新存储localStorage.setItem(STORE_KEY, theme.value);if (theme.value === 'os') {// 设置系统主题listener();// 监听系统主题变化media.addEventListener('change', listener);} else {// 移除监听media.removeEventListener('change', listener);document.documentElement.dataset.theme = theme.value;}
});export function useTheme() {return {theme}
};
demo.vue
<script setup lang="ts">import { useTheme } from '@/hooks/useTheme';const { theme } = useTheme()
</script><template><h1>JS媒体查询之matchMedia API 实现跟随系统主题色切换效果</h1><hr><select v-model="theme"><option value="ligth">亮色</option><option value="dark">暗色</option><option value="os">系统跟随</option><option value="red">红色</option><option value="green">绿色</option><option value="blue">蓝色</option></select>
</template><style>:root {--text-color: #333;--bg-color: #fff;}html[data-theme="dark"] {--text-color: #fff;--bg-color: #333;}html[data-theme="ligth"] {--text-color: #333;--bg-color: #fff;}html[data-theme="red"] {--text-color: #fff;--bg-color: #ff0064;}html[data-theme="green"] {--text-color: #fff;--bg-color: #67c23a;}html[data-theme="blue"] {--text-color: #fff;--bg-color: #0091db;}body {background-color: var(--bg-color);color: var(--text-color);}h1 {color: var(--text-color);text-align: center;}select {display: block;margin: 20px auto;font-size: 32px;}
</style>