手把手教你“手搓”网页深浅色模式切换(支持 iframe 同步!)
本文介绍了一套轻量级、无依赖的网页深浅色模式切换方案,支持iframe同步。核心原理是通过给<body>添加dark-mode类控制全局样式:默认无类名时为浅色模式,添加类名时切换为深色模式。方案包含CSS分层设计、JavaScript逻辑处理(切换、记忆和同步)以及iframe跨页面同步的实现方法。通过localStorage存储用户偏好,并提供了主页面控制iframe和iframe
本文已部署至个人博客手把手教你“手搓”网页深浅色模式切换(支持 iframe 同步!)
在现代 Web 开发中,深色模式(Dark Mode)几乎成了标配。虽然有很多 UI 库自带这个功能,但作为一个喜欢掌控细节的开发者,自己“手搓”一套方案不仅代码量小,而且能完全满足定制化需求(比如复杂的 iframe 嵌套场景)。
今天就来分享一套轻量级、无依赖、支持 iframe 同步的深浅色模式切换方案。
核心原理:一行 CSS 类的魔法
我们的实现逻辑非常简单粗暴但有效:
通过给 <body> 标签添加一个 dark-mode 类来控制全局样式。
- 默认状态:
<body>无类名 -> 浅色模式。 - 深色状态:
<body>有.dark-mode类名 -> 深色模式。
第一步:CSS 样式的分层设计
为了维护方便,我们建议采用覆盖式写法。默认写浅色样式,然后通过 CSS 优先级覆盖深色样式。
/* === 默认样式 (浅色模式) === */
.article-card {
background: #fff;
color: #333;
transition: background 0.3s, color 0.3s; /* 加上过渡动画更丝滑 */
}
/* === 深色模式 (覆盖样式) === */
/* 核心技巧:利用 body.dark-mode 提高权重 */
body.dark-mode .article-card {
background: #2a2a2a;
color: #f0f0f0;
}
提示:如果你的项目很大,建议将深色样式拆分到单独的文件中,便于管理。
第二步:JavaScript 逻辑核心
我们需要一个“大脑”来处理三个任务:
- 切换:点击按钮修改
class。 - 记忆:使用
localStorage记住用户的选择。 - 同步:确保刷新页面后主题不丢失。
在你的全局 JS文件(例如 navbar.js)中加入以下逻辑:
1. 页面加载时的自动检测
// 页面加载瞬间,立即读取偏好
// 放在 DOMContentLoaded 或 <head> 中可以减少闪烁
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
document.body.classList.add('dark-mode');
}
2. 切换按钮的点击事件
themeToggle.addEventListener('click', function() {
// 1. 切换当前 body 的类
const isDark = document.body.classList.toggle('dark-mode');
// 2. 保存状态到本地存储
localStorage.setItem('theme', isDark ? 'dark' : 'light');
// 3. 更新按钮文字或图标
this.textContent = isDark ? '🌞' : '🌙';
// 4. (进阶) 同步给子页面,见下文
syncThemeToIframe(isDark);
});
第三步:攻克难点—— Iframe 跨页面同步
很多传统网页架构使用 iframe 来加载内容,这就导致了一个痛点:主页变黑了,iframe 里面还是白的。
我们需要实现主页面与 iframe 的双向通信。
场景 A:主页面控制 iframe(父传子)
当我们在主导航栏点击切换时,需要手动去抓取 iframe 的 DOM 并修改它:
const syncThemeToIframe = (isDark) => {
const iframe = document.getElementById('contentFrame');
// 必须确保 iframe 已加载且同源
if (iframe && iframe.contentDocument && iframe.contentDocument.body) {
// 同步 toggle 类名
iframe.contentDocument.body.classList.toggle('dark-mode', isDark);
}
};
场景 B:Iframe 加载时的自我感知(子查父/存储)
当 iframe 里的页面被刷新或跳转时,它需要知道当前是什么模式。
方法 1:读取共享的 LocalStorage(推荐)
只要 iframe 和主页面同源(Domain 相同),它们共享 localStorage。
在 iframe 内部引用的 JS 中:
// iframe 内部脚本
document.addEventListener('DOMContentLoaded', function() {
// 直接读取统一的存储键值
if (localStorage.getItem('theme') === 'dark') {
document.body.classList.add('dark-mode');
}
});
方法 2:监听主框架的消息(更严谨)
在主页面的 main-frame.js 中监听 iframe 的加载事件:
iframe.addEventListener('load', () => {
// 只要主页面是黑的,加载完新的 iframe 页面后,强制把它也变黑
const isParentDark = document.body.classList.contains('dark-mode');
if (isParentDark) {
iframe.contentDocument.body.classList.add('dark-mode');
}
});
效果展示


总结与数据流图
这一套方案的数据流向非常清晰:
- 用户动作 -> 触发 JS 事件。
- DOM 操作 -> 实时修改 CSS 类(视觉反馈)。
- 持久化 -> 写入
localStorage(防止刷新丢失)。 - 传递 -> 穿透
iframe边界同步状态。
用户点击
↓
[主页面 body 变黑] ──(同步)──> [Iframe body 变黑]
↓
[写入 localStorage]
↓
(用户刷新页面)
↓
[读取 localStorage] ──> [恢复深色模式]
注意事项
- 同源策略:iframe 操作
contentDocument或共享localStorage必须要求主页面和子页面在同一个域名下。 - 样式优先级:切记深色模式的 CSS 选择器权重必须高于默认样式(使用
body.dark-mode .class即可完美解决)。 - 闪烁问题:将读取
localStorage的脚本放在 HTML 的<head>底部执行,可以最大程度避免页面先白后黑的“闪烁”现象。
希望这篇教程能帮你轻松搞定网页的“夜间模式”!快去试试吧!
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)