深色模式切換鈕可讓使用者覆寫單一網站的系統色彩配置。更新 <meta name="color-scheme"> 即可套用覆寫:light dark 表示「遵循系統偏好設定」,light 或 dark 則會固定明確的配置。顏色 (light-dark())、系統顏色和原生 UI 都會根據 CSS color-scheme 屬性進行調整,因此切換鈕會讓該屬性與 <meta> 保持同步 (請參閱「在 CSS 中反映覆寫」)。
持續顯示切換鈕、設定控制項,還是完全不顯示切換鈕?
大多數網站不需要在網站 UI (標頭、導覽、頁尾等) 中提供永久色彩配置切換鈕。根據預設,請遵循系統偏好設定,如果需要手動覆寫,請將控制項放在獨立的設定介面:設定頁面、面板或疊加層。
將配置固定在 OS 上是合理但罕見的意圖,而罕見的意圖應放在漸進式揭露機制後方,而不是放在隨時可見的控制項中。
永久切換鈕大多出現在開發人員或與開發人員相關 (例如設計師) 的網站上,因為這些網站切換配置的頻率遠高於一般網頁使用者。 請勿僅因為這是開發人員網站上的常見模式而新增:開發人員對此控制項的興趣不代表一般使用者。
導入作業
首先,請按照「深色模式」中的所有步驟操作,支援這兩種配置,並預設為系統偏好設定。
資料模型
深色模式切換鈕的資料模型通常包含三種狀態:
- 系統 (未儲存值):使用者介面會採用系統色彩配置。理想情況下,這應該是預設值。
- 淺色 (儲存為
"light"):無論系統色彩配置為何,UI 都會使用淺色主題。 - 深色 (儲存為
"dark"):無論系統色彩配置為何,UI 都會使用深色主題。
這個狀態通常會儲存在 localStorage 中,並反映在文件標頭的 <meta name="color-scheme"> 元素中。
在 CSS 中反映覆寫
<meta> 只是呈現提示:作者 CSS 中的任何 color-scheme 宣告都會覆寫該提示。由於深色模式會在 :root 上設定 color-scheme: light dark,因此單獨更新 <meta> 是無作業,CSS 會勝出。將 <meta> 對應回屬性,讓串聯遵循該屬性:
:root {
color-scheme: light dark;
&:has(> head > meta[name="color-scheme"][content="dark"]) {
color-scheme: dark;
}
&:has(> head > meta[name="color-scheme"][content="light"]) {
color-scheme: light;
}
}
請勿將 color-scheme: light 或 color-scheme: dark 硬式編碼為根預設值;基本宣告必須保持 light dark。CSS 不得依賴 JS:如果 JS 從未執行,<meta> 會維持 light dark,網站會遵循系統偏好設定,不會發生任何問題。
持續性和 FOUC 預防
將覆寫設定保留在 localStorage 中;返回系統預設值時,請移除該項目。
為避免錯誤配置閃爍,請在 <meta> 元素後方,立即使用內嵌指令碼 (非 type=module,非 defer) 套用儲存的值:
<meta name="color-scheme" content="light dark">
<script>
document.querySelector('meta[name="color-scheme"]').content = localStorage.getItem("color-scheme") ?? "light dark";
</script>
- 這個內嵌指令碼僅用於防止 FOUC。請盡可能縮小這個檔案,用於處理色彩配置切換的其他 JS 則可稍後載入。
- 在極少數情況下,
localStorage存取權可能會擲回 (例如網站資料遭到封鎖),但由於這個指令碼不會執行其他動作,因此唯一的副作用是控制台錯誤。如果這點很重要,請用try .. catch包裝。即使主題無法保留,仍要確保主題已套用至頁面。 - 覆寫值可能會從其他分頁變更:請處理
window的storage事件,保持同步。 - 當系統偏好設定變更為與儲存值相符時,請勿使用
matchMedia()移除儲存值。許多使用者的 OS 會根據時間自動切換配置;如果每次兩者剛好一致時就移除儲存的值,就完全無法固定配置。
HTML 和非顏色值的分支
顏色不需要額外處理:<meta> 對應至 color-scheme (如上) 後,light-dark() 會遵循覆寫。本節說明如何調整其他值 (例如 font-weight、媒體來源等)。
如果網頁只是遵循系統偏好設定,則可使用 (prefers-color-scheme: dark) 進行分支,包括在 <picture> 或 <video> 來源中。覆寫色彩配置會增加額外的複雜度:系統偏好設定不再是可靠資料來源,而且對於只接受媒體查詢的 API,沒有直接替代方案。
請勿完全依賴 JS 套用的類別 (例如 .dark) 進行分支,因為如果 JS 未載入且 OS 預設為深色,這些類別就會不正確。
您可以將媒體查詢與 :root:has(> head > meta[name="color-scheme"][content="dark"]) (或 light) 選取器結合,建立分支。如要瞭解如何妥善導入這項功能,請參閱「選取器和 @ 規則組合」。
控制項本身的選項也是非顏色分支:在標記中加入兩種狀態 (圖示加上視覺上隱藏的動作文字,例如「切換至深色主題」),並透過這些選取器隱藏非使用中的狀態。display: none 也會從輔助技術中移除多餘的選項,因此當系統偏好設定變更時,控制項不需要 JS 就能保持最新狀態。
如果是 HTML 內嵌媒體,目前唯一的方法是將兩個版本都納入為獨立元素,並適當切換顯示設定。使用 display: none 隱藏 <source> 元素無效。
使用者介面
兩或三個州?
在所有情況下,UI 都必須支援還原或將色彩配置設為系統。
在空間有限的切換鈕中,建議顯示兩種狀態,例如網站 Chrome (標頭、導覽、頁尾等) 中的永久切換鈕,這類切換鈕的空間有限,且調整設定通常與使用者目標無關。
在獨立設定介面 (頁面、面板或疊加層) 中,色彩配置控制項是不同的情境,可能會明確顯示所有三種狀態 (「淺色」、「深色」、「系統」):使用者已對未來行為做出審慎決定,且有空間說明選項。
如果網站採用情境感知配置 (例如 OS 處於深色模式時,採用較暗的淺色模式),則也應提供三個明確狀態,因為「淺色」和「系統 (目前為淺色)」確實不同。
雙態切換鈕
使用這類控制項時,通常是為了暫時調整舒適度 (「現在太亮了」),而不是為了確保目前狀態能長期維持。因此,對於雙態切換,只要顯示三個設定中的兩個即可:系統 (以便還原設定) 和系統目前的相反值 (儲存為目前的常值)。
只有兩種狀態:
- 系統預設:沒有儲存的值,
<meta>內容light dark。顯示為目前的解析值 (例如:淺色主題時顯示太陽圖示)。 - 覆寫:儲存為
light或dark。
基本上,這是一種三態控制項 (light dark、light、dark),其中與目前系統偏好設定相符的明確狀態無法連線。
使用者切換設定時:
- 目標配置 = 與目前顯示配置相反 (儲存的值 (如有),否則為系統偏好設定)。使用者意圖是「選取與目前所見相反的選項」,而非「選取與系統預設相反的選項」。
- 如果目標與目前的系統偏好設定不同,請直接儲存。
- 如果目標與目前的系統偏好設定相符,表示使用者正在復原調整:移除儲存的值。請勿儲存,否則會隱形固定配置,無法因應未來的系統變更。
- 將
<meta>內容設為儲存的值,如果沒有,則設為light dark。
重要事項:只能在儲存時檢查差異,絕不能追溯:如果系統偏好設定後來變更為與儲存值相符,則必須保留該儲存值。許多使用者的 OS 會根據時間自動切換配置;如果每次兩者剛好一致時就移除儲存的值,就無法固定配置。
範例情境 (OS 一開始設為淺色):
- 使用者切換。深色與系統偏好設定不同,因此系統會儲存
dark,網站會變成深色。 - OS 設定會變更為深色。網站會維持深色模式 (儲存的值現在與系統偏好設定相符,但會保留)。
- OS 設定會變回淺色。網站會保持深色模式。
- 使用者切換。目標 (淺色) 與系統偏好設定相符,因此系統會移除儲存的值,網站也會再次遵循系統設定。
三態切換鈕
如果空間較大,且使用者已準備好設定長期偏好設定,三態控制項可提供更清楚的資訊。在這種情況下,資料模型會清楚對應至三個 UI 選項:系統、淺色和深色。
為減輕認知負擔,「系統」選項也應顯示目前的系統設定,例如:
- 圖示,例如系統圖示右下方的太陽圖示
- 文字,例如「系統 (目前為淺色)」