-
多种换肤模式:
(图片来源网络,侵删)- 浅色模式:默认的经典设计。
- 深色模式:护眼的暗色主题。
- 自动模式:根据用户系统偏好自动切换。
- 自定义模式:允许用户自由选择主色调和背景色。
-
流畅的切换动画:使用 CSS 过渡效果,让主题切换更加平滑自然。
-
主题持久化:使用
localStorage保存用户的主题选择,刷新页面后不会丢失。 -
响应式设计:网站在各种设备上都能良好显示。
-
清晰的代码注释:让你能轻松理解实现原理。
(图片来源网络,侵删)
最终效果预览
实现步骤
我们将整个项目分为三个文件:
index.html:网页的结构和内容。style.css:所有主题的样式,以及切换动画。script.js:处理主题切换的逻辑。
第 1 步:HTML 结构 (index.html)
这个文件定义了网站的骨架,它包含一个主题切换器(一组按钮)和网站的主要内容区域。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">网页换肤功能演示</title>
<link rel="stylesheet" href="style.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap" rel="stylesheet">
</head>
<body class="theme-light">
<header>
<h1>网页换肤功能演示</h1>
<p>探索不同的主题模式,找到你最喜欢的设计风格。</p>
</header>
<main>
<section class="theme-switcher">
<h2>选择主题</h2>
<div class="theme-buttons">
<button class="theme-btn" data-theme="light">
<span class="theme-icon">☀️</span>
<span class="theme-name">浅色</span>
</button>
<button class="theme-btn" data-theme="dark">
<span class="theme-icon">🌙</span>
<span class="theme-name">深色</span>
</button>
<button class="theme-btn" data-theme="auto">
<span class="theme-icon">🌗</span>
<span class="theme-name">自动</span>
</button>
</div>
</section>
<section class="content-card">
<h2>这是内容卡片</h2>
<p>这段文字的颜色和背景会根据你选择的主题而改变,这得益于我们使用了 CSS 自定义属性(变量),让主题切换变得非常简单和高效。</p>
<div class="card-actions">
<button class="card-button">主要操作</button>
<button class="card-button secondary">次要操作</button>
</div>
</section>
<section class="content-card">
<h2>另一个示例卡片</h2>
<p>你可以轻松地扩展这个系统,创建更多的主题,森林绿”、“海洋蓝”或者“日落橙”,只需要在 CSS 中定义新的变量集合即可。</p>
<ul>
<li>列表项 1</li>
<li>列表项 2</li>
<li>列表项 3</li>
</ul>
</section>
</main>
<footer>
<p>© 2025 换肤功能演示. 使用 CSS 变量和 JavaScript 构建。</p>
</footer>
<script src="script.js"></script>
</body>
</html>
第 2 步:CSS 样式 (style.css)
这是实现换肤的核心,我们使用 CSS 自定义属性(CSS Variables) 来定义颜色,这使得我们只需要通过修改 body 元素的类名,就可以改变整个网站的颜色方案。
/* --- 基础样式和重置 --- */
:root {
/* 默认浅色主题的变量 */
--bg-primary: #ffffff;
--bg-secondary: #f4f4f9;
--text-primary: #333333;
--text-secondary: #666666;
--accent-color: #007bff;
--border-color: #e0e0e0;
--card-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--transition-speed: 0.3s;
}
/* 全局过渡效果,让颜色变化平滑 */
*,
*::before,
*::after {
box-sizing: border-box;
transition: background-color var(--transition-speed),
color var(--transition-speed),
border-color var(--transition-speed);
}
body {
font-family: 'Noto Sans SC', sans-serif;
margin: 0;
padding: 0;
background-color: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
}
h1, h2 {
color: var(--text-primary);
}
header {
text-align: center;
padding: 2rem;
background-color: var(--bg-secondary);
}
main {
max-width: 800px;
margin: 2rem auto;
padding: 0 1rem;
}
/* --- 主题切换器样式 --- */
.theme-switcher {
text-align: center;
margin-bottom: 2rem;
}
.theme-buttons {
display: flex;
justify-content: center;
gap: 1rem;
margin-top: 1rem;
}
.theme-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1rem;
border: 2px solid var(--border-color);
background-color: var(--bg-primary);
color: var(--text-primary);
border-radius: 12px;
cursor: pointer;
font-size: 1rem;
font-weight: 500;
transition: transform 0.2s, box-shadow 0.2s;
}
.theme-btn:hover {
transform: translateY(-3px);
box-shadow: var(--card-shadow);
}
.theme-btn.active {
border-color: var(--accent-color);
background-color: var(--accent-color);
color: white;
}
.theme-icon {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
/* --- 内容卡片样式 --- */
.content-card {
background-color: var(--bg-primary);
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: var(--card-shadow);
}
.content-card h2 {
margin-top: 0;
}
.card-actions {
display: flex;
gap: 1rem;
margin-top: 1rem;
}
.card-button {
padding: 0.7rem 1.5rem;
border: none;
border-radius: 8px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s;
}
.card-button.primary {
background-color: var(--accent-color);
color: white;
}
.card-button.secondary {
background-color: var(--bg-secondary);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
footer {
text-align: center;
padding: 1.5rem;
margin-top: 2rem;
color: var(--text-secondary);
background-color: var(--bg-secondary);
}
/* --- 深色主题变量 --- */
body.theme-dark {
--bg-primary: #121212;
--bg-secondary: #1e1e1e;
--text-primary: #f0f0f0;
--text-secondary: #b0b0b0;
--accent-color: #4a9eff;
--border-color: #333333;
--card-shadow: 0 4px 6px rgba(0, 0, 0, 0.5);
}
/* --- 自动主题的媒体查询 --- */
/* 当系统设置为深色模式时,自动应用深色主题 */
@media (prefers-color-scheme: dark) {
body.theme-auto {
--bg-primary: #121212;
--bg-secondary: #1e1e1e;
--text-primary: #f0f0f0;
--text-secondary: #b0b0b0;
--accent-color: #4a9eff;
--border-color: #333333;
--card-shadow: 0 4px 6px rgba(0, 0, 0, 0.5);
}
}
/* 响应式设计 */
@media (max-width: 600px) {
.theme-buttons {
flex-direction: column;
align-items: center;
}
.card-actions {
flex-direction: column;
}
}
第 3 步:JavaScript 逻辑 (script.js)
这个脚本负责处理用户的点击事件,修改 body 的类名,并保存用户的偏好。

(图片来源网络,侵删)
document.addEventListener('DOMContentLoaded', () => {
// 1. 获取所有主题按钮
const themeButtons = document.querySelectorAll('.theme-btn');
// 2. 从 localStorage 获取保存的主题,如果没有则使用 'auto' 作为默认值
const savedTheme = localStorage.getItem('theme') || 'auto';
// 3. 页面加载时,应用保存的主题
document.body.className = `theme-${savedTheme}`;
updateActiveButton(savedTheme);
// 4. 为每个主题按钮添加点击事件监听器
themeButtons.forEach(button => {
button.addEventListener('click', () => {
const selectedTheme = button.getAttribute('data-theme');
// 更新 body 的类名
document.body.className = `theme-${selectedTheme}`;
// 更新活动按钮的样式
updateActiveButton(selectedTheme);
// 将用户选择的主题保存到 localStorage
localStorage.setItem('theme', selectedTheme);
});
});
/**
* 更新主题按钮的激活状态
* @param {string} activeTheme - 当前激活的主题名称
*/
function updateActiveButton(activeTheme) {
themeButtons.forEach(button => {
if (button.getAttribute('data-theme') === activeTheme) {
button.classList.add('active');
} else {
button.classList.remove('active');
}
});
}
// 可选:监听系统主题变化,当用户选择 'auto' 时动态切换
// 注意:这个功能需要页面加载时已经是 'auto' 模式才有效
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
if (document.body.classList.contains('theme-auto')) {
// 这里不需要手动切换,因为 CSS 的媒体查询会自动处理
// 但我们可以在这里添加一些逻辑,比如通知用户系统主题已改变
console.log('系统主题已更改为:', e.matches ? '深色' : '浅色');
}
});
});
如何运行
- 创建文件:在你的电脑上创建一个名为
theme-demo的文件夹,然后在其中创建index.html、style.css和script.js三个文件。 - 复制代码:将上面提供的代码分别粘贴到对应的文件中。
- 打开浏览器:用 Chrome、Firefox 或 Edge 等现代浏览器打开
index.html文件。 - 体验功能:点击“浅色”、“深色”和“自动”按钮,观察网站的变化,刷新页面,你会发现你选择的主题被保留了。
核心技术点总结
- CSS 自定义属性 (变量):这是实现换肤的关键,将颜色定义为变量(如
--bg-primary),然后在需要的地方使用var(--bg-primary)引用,切换主题时,只需改变这些变量的值。 - HTML Class 切换:通过 JavaScript 修改
body的类名(如theme-light,theme-dark),来加载不同的 CSS 变量集合。 localStorage:用于在客户端持久化存储用户的主题偏好,即使用户关闭了浏览器或刷新了页面,设置依然有效。prefers-color-scheme:这是一个强大的 CSS 媒体查询,可以检测用户的操作系统是否设置了深色模式,是实现“自动模式”的基础。- 平滑过渡 (
transition):为颜色相关的属性添加过渡效果,能让用户体验更加流畅和愉悦。
这个实现方案既简单又强大,是现代 Web 开发中实现换肤功能的标准做法,你可以基于这个框架,轻松地扩展出更多、更复杂的主题。
