实现网页暗黑模式时,不少开发者会遇到切换为暗黑模式后刷新页面,主题又回到默认亮色模式的问题,这会影响用户的使用体验。该问题的核心原因通常是主题状态的读取和应用时机晚于页面渲染,或者状态存储方式存在缺陷。

问题产生的常见原因
页面加载时暗黑模式未激活,主要有以下几个常见诱因:
- 主题状态没有持久化存储,刷新页面后状态丢失,默认回到初始的亮色模式
- 读取存储的主题状态的操作放在了DOM加载完成之后,导致页面先渲染了默认样式,再切换到暗黑模式,出现闪屏
- CSS的暗黑模式样式优先级不足,被默认样式覆盖,无法正常生效
- 读取存储状态时出现错误,比如localStorage被清空或者读取的值不符合预期,没有做容错处理
解决方案实现步骤
1. 定义暗黑模式的CSS样式
首先需要定义暗黑模式对应的CSS变量和样式,建议将暗黑模式的样式放在默认样式之后,并且通过属性选择器或者类名来控制生效范围。
/* 默认亮色模式变量 */
:root {
--bg-color: #ffffff;
--text-color: #333333;
--card-bg: #f5f5f5;
}
/* 暗黑模式变量,通过data-theme属性控制 */
:root[data-theme="dark"] {
--bg-color: #1a1a1a;
--text-color: #e5e5e5;
--card-bg: #2d2d2d;
}
/* 全局应用变量 */
body {
background-color: var(--bg-color);
color: var(--text-color);
transition: background-color 0.3s, color 0.3s;
}
.card {
background-color: var(--card-bg);
padding: 16px;
border-radius: 8px;
margin: 16px 0;
}
2. 使用localStorage持久化存储主题状态
用户在切换主题时,需要将当前主题状态存储到localStorage中,保证刷新页面后状态不会丢失。
// 切换主题的函数
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
// 设置根元素的主题属性
document.documentElement.setAttribute('data-theme', newTheme);
// 将主题状态存储到localStorage
localStorage.setItem('site_theme', newTheme);
}
// 绑定切换按钮的事件
document.getElementById('theme-toggle-btn').addEventListener('click', toggleTheme);
3. 在页面加载早期读取并应用主题
为了避免页面先渲染默认样式再切换导致的闪屏问题,需要在页面渲染之前就读取存储的主题状态并应用到根元素上。可以将这段脚本放在<head>标签内,CSS引入之后,DOM渲染之前的位置。
// 页面加载早期执行,避免闪屏
(function() {
// 读取localStorage中存储的主题状态
const savedTheme = localStorage.getItem('site_theme');
// 如果没有存储的状态,默认使用亮色模式
const theme = savedTheme || 'light';
// 直接设置根元素的data-theme属性
document.documentElement.setAttribute('data-theme', theme);
})();
4. 处理状态读取的异常情况
实际使用中可能会出现localStorage不可用、存储的值异常的情况,需要增加容错处理,保证主题功能稳定。
(function() {
let theme = 'light';
try {
const savedTheme = localStorage.getItem('site_theme');
// 校验存储的值是否合法,只接受light或者dark
if (savedTheme === 'dark' || savedTheme === 'light') {
theme = savedTheme;
}
} catch (e) {
// localStorage不可用时使用默认主题
console.error('读取主题状态失败', e);
}
document.documentElement.setAttribute('data-theme', theme);
})();
完整示例代码
以下是一个完整的HTML示例,包含主题切换按钮和完整的逻辑实现:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>暗黑模式示例</title>
<style>
:root {
--bg-color: #ffffff;
--text-color: #333333;
--card-bg: #f5f5f5;
}
:root[data-theme="dark"] {
--bg-color: #1a1a1a;
--text-color: #e5e5e5;
--card-bg: #2d2d2d;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
transition: background-color 0.3s, color 0.3s;
font-family: sans-serif;
padding: 20px;
}
.card {
background-color: var(--card-bg);
padding: 16px;
border-radius: 8px;
margin: 16px 0;
}
#theme-toggle-btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
background-color: var(--card-bg);
color: var(--text-color);
}
</style>
<script>
// 早期加载主题,避免闪屏
(function() {
let theme = 'light';
try {
const savedTheme = localStorage.getItem('site_theme');
if (savedTheme === 'dark' || savedTheme === 'light') {
theme = savedTheme;
}
} catch (e) {
console.error('读取主题状态失败', e);
}
document.documentElement.setAttribute('data-theme', theme);
})();
</script>
</head>
<body>
<h1>暗黑模式演示页面</h1>
<button id="theme-toggle-btn">切换暗黑模式</button>
<div class="card">
<p>这是一个卡片内容,用于展示暗黑模式和亮色模式的样式差异。</p>
</div>
<p>切换主题后刷新页面,主题状态会保持,不会出现加载时未激活的问题。</p>
<script>
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('site_theme', newTheme);
}
document.getElementById('theme-toggle-btn').addEventListener('click', toggleTheme);
</script>
</body>
</html>
注意事项
实现过程中还需要注意以下几点:
- 不要在
<body>的onload事件中读取主题状态,这个时机太晚,必然会出现闪屏 - 如果使用了服务端渲染,需要在服务端就根据存储的主题状态输出对应的根元素属性,避免客户端二次切换
- 如果用户清除了浏览器数据,localStorage中的主题状态会被清空,此时会回到默认主题,属于正常情况
- 暗黑模式的颜色对比度需要符合 accessibility 标准,避免文字和背景对比度过低导致用户阅读困难
JavaScript暗黑模式localStorage页面加载主题切换修改时间:2026-06-10 03:06:37