使用 Astro+Tailwind 實現 Dark mode
紀錄如何使用 Astro+Tailwind 來實現 Dark mode 功能,並將狀態儲存在 localStorage,每次進入時檢查 localStorage 的 theme 來切換 mode
安裝 Tailwind
在 Astro 中有 astro add
指令來自動整合套件,可以直接在終端機輸入
npx astro add tailwind
接著他會問你是否繼續,以及幫你建立 tailwind.config.cjs
檔案,這邊就都 Yes 就可以了
結束後,你應該會看到根目錄幫你建立好 tailwind.config.cjs
檔案,以及在 astro.config.mjs
設定中的 integrations 裡看到多了一個 tailwind()
如果有問題也能參考一下官方文件
啟用 Dark mode
在剛剛安裝完後,你的 tailwind.config.cjs
大致上會長這樣
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {},
},
plugins: [],
}
這時我們可以來啟用 Tailwind 的 Dark mode
只需要在 module 中多加一個 darkMode
就可以了
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
darkMode: 'class', // or 'media' for system preference
theme: {
extend: {},
},
plugins: [],
}
darkMode 有兩種選項
- class:透過 class 手動切換模式
- media:當裝置設定是在深色模式時會自動切換模式
功能實作
這邊使用 React 元件實作,模式有 light
和 dark
一開始會先檢查用戶的主題偏好,如果是深色模式就直接回傳 dark
再來製作按鈕的 click function,如果當前 theme 是 light
則切換成 dark
,反之,同時儲存到 localStorage 中
接著製作切換頁面模式的 function,如果在 light 模式就移除 root 的 dark class,否則新增 dark class
const themes = ['light', 'dark']
export default function ThemeToggle() {
const getInitialTheme = () => {
// 檢查用戶主題偏好
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
return localStorage.getItem('theme');
}
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
}
return 'light';
};
const [theme, setTheme] = useState(getInitialTheme());
// Click Function
const toggleTheme = () => {
const newTheme = theme === 'light' ? 'dark' : 'light';
localStorage.setItem('theme', newTheme);
setTheme(newTheme);
};
useEffect(() => {
applyTheme();
}, [theme]);
const applyTheme = () => {
const root = document.documentElement;
if (theme === 'light') {
root.classList.remove('dark');
} else {
root.classList.add('dark');
}
};
return (
<div>
{themes.map((t) => (
<button
key={t}
type="button"
onClick={toggleTheme}
className={`p-2 rounded ${
theme === t ? 'bg-gray-200 dark:bg-gray-800 text-black dark:text-white' : ''
}`}
>
{t}
</button>
))}
</div>
);
}
最後再把他匯入到畫面上就可以運作了
不過,有個小問題,可能會發現換頁時會有短暫閃爍,這跟元件渲染機制有關,因為當換頁時元件會觸發重新渲染,因此 dark mode 也就會重新新增一次
可以嘗試在畫面中加入這段 <script>
直接在客戶端去檢查 localStorage 加入 theme,避免元件重新渲染時造成的畫面閃爍問題
<script is:inline>
if (typeof window !== "undefined") {
const theme = localStorage.getItem('theme');
if (theme === 'dark' || theme === 'light') {
document.documentElement.classList.add(theme);
}
}
</script>
撰寫 style
上述功能如果都順利的話,應該可以發現 <html>
標籤上會多一個 class,能夠去切換 class="light"
或 class="dark"
接著就可以來撰寫樣式了
寫法 dark: style
<div class="bg-white dark:bg-black">
<p class="dark:text-white">這是一段文字</p>
</div>