網(wǎng)頁深色模式切換:簡單實(shí)現(xiàn)方法與平滑動畫效果

現(xiàn)在很多網(wǎng)站都提供了深色模式功能。一個(gè)好的深色模式切換不僅要能改變顏色,還要有流暢的動畫效果,并且能記住用戶的選擇。下面我們來學(xué)習(xí)如何實(shí)現(xiàn)這個(gè)功能。
基本實(shí)現(xiàn)思路
1. 準(zhǔn)備兩套顏色方案
首先需要為網(wǎng)站設(shè)計(jì)淺色和深色兩套顏色。建議使用 css 變量來管理這些顏色:
:root {
--bg-color: #ffffff;
--text-color: #000000;
--border-color: #dddddd;
}
[] {
--bg-color: #121212;
--text-color: #ffffff;
--border-color: #333333;
}2. 在網(wǎng)頁中使用這些顏色
定義好顏色變量后,在整個(gè)網(wǎng)站中使用它們:
body {
background-color: var(--bg-color);
color: var(--text-color);
transition: background-color 0.3s ease, color 0.3s ease;
}
.card {
background-color: var(--bg-color);
border: 1px solid var(--border-color);
}3. 添加切換按鈕
在 html 中添加一個(gè)切換按鈕:
完整的代碼示例
HTML 結(jié)構(gòu)
<!DOCTYPE html>
<htmllang="zh-CN" >="light">
<head>
<metacharset="UTF-8">
<metaname="viewport"content="width=device-width, initial-scale=1.0">
<title>深色模式演示</title>
<linkrel="stylesheet"href="style.css">
</head>
<body>
<header>
<h1>我的網(wǎng)站</h1>
<buttonid="theme-toggle">切換到深色模式</button>
</header>
<main>
<divclass="card">
<h2>內(nèi)容標(biāo)題</h2>
<p>這是一段示例文本,用來展示深色模式下的效果。</p>
</div>
</main>
<scriptsrc="script.js"></script>
</body>
</html>CSS 樣式
/* 定義顏色變量 */
:root {
--bg-color: #ffffff;
--text-color: #000000;
--card-bg: #f8f9fa;
--border-color: #dee2e6;
--primary-color: #007bff;
}
[] {
--bg-color: #121212;
--text-color: #e9ecef;
--card-bg: #1e1e1e;
--border-color: #495057;
--primary-color: #4dabf7;
}
/* 應(yīng)用樣式 */
body {
margin: 0;
font-family: system-ui, -apple-system, sans-serif;
background-color: var(--bg-color);
color: var(--text-color);
transition: background-color 0.3s ease, color 0.3s ease;
line-height: 1.6;
}
header {
padding: 1rem2rem;
border-bottom: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
}
main {
padding: 2rem;
max-width: 800px;
margin: 0 auto;
}
.card {
background-color: var(--card-bg);
padding: 1.5rem;
border-radius: 8px;
border: 1px solid var(--border-color);
transition: all 0.3s ease;
}
button {
background-color: var(--primary-color);
color: white;
border: none;
padding: 0.5rem1rem;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s ease;
}
button:hover {
opacity: 0.9;
}JavaScript 邏輯
classThemeManager {
constructor() {
this.toggleButton = document.getElementById('theme-toggle');
this.htmlElement = document.documentElement;
this.init();
}
init() {
// 從本地存儲獲取主題設(shè)置,如果沒有就使用系統(tǒng)偏好
const savedTheme = localStorage.getItem('theme');
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const initialTheme = savedTheme || (systemPrefersDark ? 'dark' : 'light');
this.setTheme(initialTheme);
// 監(jiān)聽按鈕點(diǎn)擊
this.toggleButton.addEventListener('click', () =>this.toggleTheme());
// 監(jiān)聽系統(tǒng)主題變化
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
this.setTheme(e.matches ? 'dark' : 'light');
}
});
}
setTheme(theme) {
this.htmlElement.setAttribute('>, theme);
localStorage.setItem('theme', theme);
this.updateButtonText(theme);
}
toggleTheme() {
const currentTheme = this.htmlElement.getAttribute('>);
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
this.setTheme(newTheme);
}
updateButtonText(theme) {
this.toggleButton.textContent = theme === 'dark' ? '切換到淺色模式' : '切換到深色模式';
}
}
// 初始化主題管理器
new ThemeManager();高級動畫效果
如果想要更炫酷的切換效果,可以使用 View Transitions api:
class AdvancedThemeManager extends ThemeManager {
async toggleTheme() {
// 檢查瀏覽器是否支持 View Transitions API
if (!document.startViewTransition) {
returnsuper.toggleTheme();
}
const currentTheme = this.htmlElement.getAttribute('>);
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
// 使用 View Transitions API 創(chuàng)建平滑過渡
const transition = document.startViewTransition(() => {
this.setTheme(newTheme);
});
try {
await transition.finished;
} catch (error) {
console.log('主題切換動畫完成');
}
}
}
// 使用高級主題管理器
new AdvancedThemeManager();在流行框架中的實(shí)現(xiàn)
React 版本
import { useState, useEffect } from'react';
function useTheme() {
const [theme, setTheme] = useState('light');
useEffect(() => {
const saved = localStorage.getItem('theme');
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
setTheme(saved || (systemDark ? 'dark' : 'light'));
}, []);
const toggleTheme = () => {
const newTheme = theme === 'dark' ? 'light' : 'dark';
setTheme(newTheme);
localStorage.setItem('theme', newTheme);
document.documentElement.setAttribute('>, newTheme);
};
return [theme, toggleTheme];
}
function ThemeToggle() {
const [theme, toggleTheme] = useTheme();
return (
<button onClick={toggleTheme}>
{theme === 'dark' ? '淺色模式' : '深色模式'}
</button>
);
}vue 版本
<template>
<button @click="toggleTheme">
{{ theme === 'dark' ? '淺色模式' : '深色模式' }}
</button>
</template>
<script>
import { ref, onMounted } from'vue'
exportdefault {
setup() {
const theme = ref('light')
const toggleTheme = () => {
theme.value = theme.value === 'dark' ? 'light' : 'dark'
localStorage.setItem('theme', theme.value)
document.documentElement.setAttribute('>, theme.value)
}
onMounted(() => {
const saved = localStorage.getItem('theme')
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches
theme.value = saved || (systemDark ? 'dark' : 'light')
document.documentElement.setAttribute('>, theme.value)
})
return { theme, toggleTheme }
}
}
</script>重要注意事項(xiàng)
- 性能優(yōu)化
- 只對顏色相關(guān)的屬性添加過渡動畫
- 避免對大量元素同時(shí)進(jìn)行復(fù)雜動畫
- 使用 will-change: opacity, color, background-color 提示瀏覽器優(yōu)化
- 可訪問性
- 確保顏色對比度符合 WCAG 標(biāo)準(zhǔn)
- 為色盲用戶提供足夠的視覺區(qū)分
- 不要完全依賴顏色來傳達(dá)信息
- 測試要點(diǎn)
- 在不同瀏覽器中測試效果
- 檢查移動設(shè)備上的表現(xiàn)
- 驗(yàn)證打印樣式是否正常
常見問題解決
頁面加載時(shí)閃爍怎么辦?在 HTML 的 head 部分添加內(nèi)聯(lián)腳本快速設(shè)置主題:
<script>
const savedTheme = localStorage.getItem('theme');
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
document.documentElement.setAttribute('>,
savedTheme || (systemDark ? 'dark' : 'light')
);
</script>如何支持更多主題?可以擴(kuò)展顏色變量系統(tǒng):
[] {
--bg-color: #f0f8ff;
--text-color: #003366;
--primary-color: #007bff;
}
[] {
--bg-color: #f8fff0;
--text-color: #1a331a;
--primary-color: #28a745;
}總結(jié)
實(shí)現(xiàn)一個(gè)完整的深色模式功能需要綜合考慮顏色設(shè)計(jì)、動畫效果、用戶偏好和性能優(yōu)化。通過 CSS 變量、JavaScript 控制和適當(dāng)?shù)膭赢嫞梢詣?chuàng)建出既美觀又實(shí)用的主題切換功能。






















