「及時」模式:全新世代的 Tailwind CSS
Tailwind CSS on GitHub

深色模式 (Dark Mode)

用 Tailwind CSS 讓你的網站進入深色模式

基本用法

深色模式是現在許多作業系統都有的超夯功能,幫你的網站設計出一個深色的主題是勢在必行的。

為了使你的改造之路變得更加輕鬆愉快,Tailwind 本身就提供了一個叫做 dark 的模式變化,當瀏覽器或作業系統開啟深色模式時,你的網站可以有不同的樣式。

<div class="bg-white dark:bg-gray-800">
  <h1 class="text-gray-900 dark:text-white">這裡是深色模式 !</h1>
  <p class="text-gray-600 dark:text-gray-300">
    Lorem ipsum...
  </p>
</div>

但這邊有一件事情要注意一下,因為檔案大小的關係,在 Tailwind 中深色模式的狀態判斷預設是關閉的。

如果要打開深色模式,請把你 tailwind.config.jsdarkMode 選項的值改成 media 。

// tailwind.config.js
module.exports = {
  darkMode: 'media',
  // ...
}

現在,只要使用者的作業系統有開啟深色模式,那麼有 dark: 開頭的這些類別都會蓋過自己原本的樣式。其實 media 就是在背後使用了 色彩偏好方案 (prefers-color-scheme),但是如果你想要手動切換深色模式的效果,你可以使用 class 參數 來控制它。

一般來說,開啟 darkMode 只會幫你把跟顏色有關的 class (類別) 增加 dark 的狀態判斷,像是文字顏色、背景顏色、邊框顏色、漸層和 placeholder 的顏色。


搭配其它的變化來使用

dark 的變化模式也能與其它的變化搭在一起使用,比如響應式變化,和狀態變化模式 (像是 hover 和 focus):

<button class="lg:dark:hover:bg-white ...">
  <!-- ... -->
</button>

響應式變化需要放在第一個,接著是 dark,狀態變化要放在最後面,這樣才能正常運作。


幫其它的 功能(Utilities) 開啟深色模式

如果要幫其它的 功能(utilities) 打開 dark 的模式變化,只需要在變化模式的清單中,幫你想要開啟深色模式的功能加上 dark 參數,像是:

// tailwind.config.js
module.exports = {
  // ...
  variants: {
    extend: {
      textOpacity: ['dark']
    }
  }
}

在預設情況下, dark 的模式變化只會幫 backgroundColor, borderColor, gradientColorStops, placeholderColor, and textColor 這幾個 功能 (Utilities) 開啟。


深色模式的手動切換

如果你想要跟系統的偏好設定不一樣、能夠讓你手動切換深色模式的話,那麼你就要使用 class 這個參數,來取代原本的 media

// tailwind.config.js
module.exports = {
  darkMode: 'class',
  // ...
}

現在,有 dark: 開頭的這些類別會根據 <html> 標籤裡的class 是否有 dark 來做對應的變化,而不是根據原本的 色彩偏好方案(prefers-color-scheme)。

<!-- 深色模式還沒開啟 -->
<html>
<body>
  <!-- 所以背景還是白色 -->
  <div class="bg-white dark:bg-black">
    <!-- ... -->
  </div>
</body>
</html>

<!-- 深色模式開啟了 -->
<html class="dark">
<body>
  <!-- 背景就變成黑色了 -->
  <div class="bg-white dark:bg-black">
    <!-- ... -->
  </div>
</body>
</html>

其實隨便看你要用什麼方法來幫 <html> 標籤增加 dark 這個 class,不過通常都是寫一點點簡單的 js ,然後從像是本地端之類的地方去讀取設定檔,然後再去更新 DOM 節點。

下面有一個簡單的範例,是教你怎麼做到 淺色模式深色模式,和 根據作業系統的偏好設定

// 最好在頁面讀取或更換主題的時候增加一行到 `head`來避免 FOUC
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
  document.documentElement.classList.add('dark')
} else {
  document.documentElement.classList.remove('dark')
}

// 當使用者選擇 淺色模式 時
localStorage.theme = 'light'

// 當使用者選擇 深色模式 時
localStorage.theme = 'dark'

// 當使用者選擇 根據作業系統偏好設定 時
localStorage.removeItem('theme')

同樣的,你可以根據自己的心情喜好去管理它 (就看你今天爽不爽這樣),甚至是你想要把每個使用者的偏好設定都存在你伺服器的資料庫,然後再讀出來設定頁面,都隨便你。

特性的考慮

當 darkMode 參數設為 class 時, 深色模式功能的特性優先權會高於一般的功能,因為選擇器包含了一個額外的 class。這代表某些情況下,有的功能組合後的效果在 classmedia 模式下會有些微的差異。

舉個例,先參考一下這個 HTML:

<div class="text-black text-opacity-50 dark:text-white">
  <!-- ... -->
</div>

當 darkMode 參數設為 media 時,dark:text-white 就會和 text-black 一樣擁有 text-opacity-50 這個特性。因為在生成 CSS 時,text-opacity-50 定義的時間比 dark:text-white 晚,所以白色的文字才會擁有 50% 的透明度。

而當參數設為 class 時,dark:text-white 特性的優先權會 提高,所以即使把定義的時間提前一點,它也會把 text-opacity-50 的效果覆蓋掉並重設回 1 。所以如果使用的是 class 參數,你就必須用深色模式中重新指定一次透明度,以確保特性存在:

<div class="text-black text-opacity-50 dark:text-white dark:text-opacity-50">
  <!-- ... -->
</div>