Nuxt3App顏色模式
透過html結構裡的上下層繼承變數的特性,當上層變數指向的背景色、文字色改變時,下層的樣式即可響應。
css配置
在document html樹狀結構中,html或body都可以作為綁定的上層。這裡預設一個body預設的樣式對照,使用了css變數的語法(ex. --mode-text-color:rgba(0, 0, 0, 0.8)😉;而另一個深色模式則是多了一個class名稱的body。
body.light-mode {
background-color: #fff;
color: rgba(0, 0, 0, 0.8);
--mode-text-color: rgba(0, 0, 0, 0.8);
--mode-text-color-hover: #6d28d9;
--border-color: #ccc;
}
body.dark-mode {
background-color: #091a28;
color: #ebf4f1;
--mode-text-color: #ebf4f1;
--mode-text-color-hover: #6d28d9;
--border-color: #fff;
}
在html渲染結果對照


而在下層的樣式中,就可以使用上層定義好的變量。
.tocBox {
border-color: var(--border-color);
}
.prose {
color: var(--mode-text-color);
}
取得作業系統的顏色模式
瀏覽器可以取得使用者作業系統的顏色模式,再讓javascript來讀取,這部分的資訊儲存於media內。並且多一個監聽事件,在使用者改變系統顏色模式時來響應。
window.matchMedia('(prefers-color-scheme: dark)').matches :Boolean
window
.matchMedia("(prefers-color-scheme: dark)")
.addEventListener("change", function (event) {
console.log(event.matches)
}
自訂可切換的顏色模式
跟使用者作業系統的顏色模式相對脫鉤,我預想是把顏色模式儲存於瀏覽器的localstorage,對於使用者切換上更便利,不需要再去改動作業系統的顏色模式。
//可以先抓取作業系統的顏色模式
let mode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : null;
//再抓取使用者存取瀏覽器操作的顏色模式紀錄
mode = localStorage.getItem('app-color-mode') ?? (mode ?? 'light');
//最後去把目標的上層html tag綁定對應顏色模式的class名稱
document.getElementsByTagName('body')[0].setAttribute('class', `${mode}-mode`);
ServerSideRender和ClientSideRender差異
window和document物件必須是在Client端的瀏覽器運行時才能使用,所以當渲染機制是使用SSR時,就必須注意這段取得和判別顏色模式的腳本是在client端發生,才能符合這次介紹的顏色模式機制。
//Nuxt3 SSR情境下,判別的腳本寫在onMounted這個hook中
onMounted(() => {
let mode = localStorage.setItem('nuxt3-app-color-mode', mode) ?? 'light'
document?.getElementsByTagName('body')[0]?.setAttribute('class', `${mode}-mode`);
});
同時在nuxt3框架之下,狀態管理的方式可以這樣使用,來實作切換功能。
const colorEnum = {
DARK: 'dark',
LIGHT: 'light',
SEPIA: 'sepia',
};
const appMode = useState('appMode', () => null);
const handleAppMode = () => {
switch (appMode.value) {
case colorEnum.LIGHT: {
appMode.value = colorEnum.DARK;
break;
}
case colorEnum.DARK: {
appMode.value = colorEnum.SEPIA;
break;
}
case colorEnum.SEPIA: {
appMode.value = colorEnum.LIGHT;
break;
}
}
setTimeout(() => {
addModeClass(appMode.value);
}, 100);
};
參考
How to Watch for System Dark Mode Changes Using JavaScript and CSS