1. 背景:
暗黑模式在前端是一个非常常见的需求,这里分享一下我的思路,大家如果有更好的方式可以分享一下。效果展示如下:
2. 步骤
- 定义两种模式下的颜色变量
- 获取系统的模式,并进行持久化存储
- 切换模式,并进行持久化存储
3. 代码实现
3.1 使用css定义两个模式下的颜色变量
<style>
[data-theme="light"] {
--background-color: white;
}
[data-theme="dark"] {
--background-color: black;
}
body {
background-color: var(--background-color);
}
.box {
width: 200px;
height: 200px;
background-color: green;
}
</style>
3.2 获取系统的模式,并进行持久化存储
这里需要前调一下,获取系统的模式是指电脑的模式,并不是浏览器的模式哦。
(1)第一种:通过css获取系统模式(这种方式是直接根据系统模式来自动切换,只适用于仅有跟随系统模式的功能)
@media (prefers-color-scheme: dark) {
:root {
--background-color: black;
}
}
@media (prefers-color-scheme: light) {
:root {
--background-color: white;
}
}
(2)第二种:通过js获取系统模式 (我使用的是这种,自己写逻辑)
<div class="box"></div>
<button class="toggle">切换模式</button>
<button class="system">跟随系统</button>
<script>
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)')
const body = document.querySelector('body')
if (JSON.parse(localStorage.getItem('sync_system'))) {
if (prefersDarkScheme.matches) {
body.dataset.theme = "dark"
} else {
body.dataset.theme = "light"
}
}
const system = document.querySelector('.system')
system.addEventListener('click', () => {
updateTheme(prefersDarkScheme.matches, true)
})
const updateTheme = (isDark, isSyncSystem) => {
body.dataset.theme = isDark ? "dark" : "light"
localStorage.setItem('sync_system', isSyncSystem)
}
</script>
3.3 切换模式,并进行持久化存储
<div class="box"></div>
<button class="toggle">切换模式</button>
<button class="system">跟随系统</button>
<script>
const body = document.querySelector('body')
body.dataset.theme = localStorage.getItem('theme') || 'light'
const toggle = document.querySelector('.toggle')
toggle.addEventListener('click', () => {
updateTheme(body.dataset.theme !== "dark", false)
})
const updateTheme = (isDark, isSyncSystem) => {
body.dataset.theme = isDark ? "dark" : "light"
localStorage.setItem('theme', body.dataset.theme)
}
</script>
4. 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>夜间模式</title>
<style>
[data-theme="light"] {
--background-color: white;
}
[data-theme="dark"] {
--background-color: black;
}
body {
background-color: var(--background-color);
}
.box {
width: 200px;
height: 200px;
background-color: green;
}
</style>
</head>
<body>
<div class="box"></div>
<button class="toggle">切换模式</button>
<button class="system">跟随系统</button>
<script>
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)')
const body = document.querySelector('body')
if (JSON.parse(localStorage.getItem('sync_system'))) {
if (prefersDarkScheme.matches) {
body.dataset.theme = "dark"
} else {
body.dataset.theme = "light"
}
} else {
body.dataset.theme = localStorage.getItem('theme') || 'light'
}
const toggle = document.querySelector('.toggle')
const system = document.querySelector('.system')
toggle.addEventListener('click', () => {
updateTheme(body.dataset.theme !== "dark", false)
})
system.addEventListener('click', () => {
updateTheme(prefersDarkScheme.matches, true)
})
const updateTheme = (isDark, isSyncSystem) => {
body.dataset.theme = isDark ? "dark" : "light"
localStorage.setItem('sync_system', isSyncSystem)
localStorage.setItem('theme', body.dataset.theme)
}
</script>
</body>
</html>