Preferencess-color-scheme:嗨,黑暗,我的老朋友

過度或急需?瞭解深色模式的所有相關知識,以及如何支援這項功能,為使用者帶來益處!

簡介

深色模式前使用深色模式

綠幕電腦顯示器
綠幕 (來源)

我們已在深色模式中呈現整個圓圈。在個人運算的時代,您也無法選擇深色模式,但值得注意的是:單色 CRT 電腦螢幕的運作原理是在磷光螢幕上啟動電子光束,而早期 CRT 中所用的現象則為綠色。由於文字顯示為綠色,而畫面的其餘部分則為黑色,因此這些模型通常稱為「綠色螢幕」

深白文字處理
Dark-on-white (來源)

後續引進的色彩 CRT 透過使用紅、綠和藍光譜,顯示多種顏色。他們同時對全部三個發光現象創造出白色光澤。 隨著 WYSIWYG 電腦發布的問世,虛擬文件就像實體紙片的誕生,變得越來越受歡迎。

全球 WideWeb 瀏覽器中的深白網頁
WorldWideWeb 瀏覽器 (來源)

這裡的「dark-on-white」便是設計趨勢的起點,而這種趨勢已移至早期文件型網路。史上第一個瀏覽器 WorldWideWeb (請記住,CSS 尚未發明), 以這種方式顯示網頁。 趣聞新知:第二款瀏覽器是「線性模式瀏覽器」(這是終端式瀏覽器),在深色的情況下呈現綠色。現今的網頁和網頁應用程式,通常是在淺色背景上以深色文字設計,一種基準假設,也以硬式編碼方式寫入使用者代理程式樣式表,包括 Chrome

躺在床上時使用智慧型手機
智慧型手機在床上使用 (資料來源:Unsplash)

CRT 過了一段時間,使用背光 LCD 或省電 AMOLED 螢幕的行動裝置,已改為使用及製作內容。規模各異的電腦、平板電腦和智慧型手機衍生出新的使用模式。 網路瀏覽、專為娛樂寫程式編寫的程式碼,以及高檔遊戲經常在昏暗的環境中發生。大家甚至在晚上也能在床上選購裝置。 越來越多人在昏暗環境中使用裝置,因此返回淺色中 (light-on) 的根層級越大受歡迎。

為什麼要使用深色模式

深色模式是為了美觀

當使用者詢問他們喜歡或想要深色模式的原因時,最常見的回應是「眼睛比較容易,」接著會接著是「纖細又美麗」。Apple 在深色模式開發人員說明文件明確寫出以下內容:「對大多數使用者來說,啟用淺色或深色外觀是美觀的選擇,不涉及環境光照條件。」

在 Mac OS System 7 中關閉 CloseView
系統 7 CloseView (來源)

深色模式做為無障礙工具

也有使用者確實「需要」深色模式,並做為另一種無障礙工具,例如低視能使用者。我找到的這類無障礙工具最早出現了 System 7CloseView 功能,當中的「Black on White」和「White on Black」切換鈕。 雖然系統 7 支援的顏色,但預設使用者介面仍為黑白。

這些反轉式實作案例,在套用色彩後,展現出本身的弱點。Szpiro 等人進行的使用者研究指出,低視能存取運算裝置的使用者都不喜歡圖片反轉圖片,但在深色背景上有許多偏好的淺色文字。Apple 可運用名為「Smart Invert」的功能,反轉螢幕上的色彩,藉此滿足這個使用者偏好,但圖片、媒體和部分使用深色樣式的應用程式除外。

電腦視覺合成器是一種特殊形式的低視能 (又稱為 Digital Eye Strain),定義「眼睛和視力問題組合」,也就是與電腦 (包括桌上型電腦、筆記型電腦和平板電腦) 和其他電子螢幕 (例如智慧型手機和電子閱讀裝置) 使用的相關問題。" 最近建議青少年使用電子裝置,特別是在夜間,可能會降低睡眠時長、睡眠時長延遲及增加睡眠不足的風險。此外,由於藍光的曝露至今已廣泛回報涉及生理時鐘和睡眠週期,而不規則光線環境可能會導致睡眠不足,進而影響心情和工作表現 (根據 Rosenfield 的研究)。為減少這類負面影響,透過 iOS 的 Night Shift 或 Android 的 Night Light 等功能調整螢幕色溫,有助於減少藍光,並透過深色主題或深色模式避免一般光線或較不規律的光線。

在 AMOLED 螢幕上利用深色模式省電

最後,深色模式的用途是在 AMOLED 螢幕上節省大量能源。以 YouTube 等熱門 Google 應用程式為主的 Android 個案研究顯示,節省電力最多可達 60%。下方影片將進一步說明這類個案研究,以及每個應用程式節省的電力。

在作業系統中啟用深色模式

瞭解過深色模式對許多使用者的重要性後,接著來看看該如何支援。

Android Q 深色模式設定
Android Q 深色主題設定

一般來說,支援深色模式或深色主題的作業系統通常能在設定的特定位置啟動該模式。在 macOS X 上,該圖示位於系統偏好設定的「General」部分,稱為「Appearance」 (螢幕截圖);在 Windows 10 中,則位於「Colors」部分,名為「Choose your color」 (螢幕截圖)。如果是 Android Q,您可以在「Display」下方找到「Dark Theme」切換開關 (螢幕截圖);如果是 iOS 13,則可在設定的「顯示與亮度」部分變更「外觀」 (螢幕截圖)。

prefers-color-scheme 媒體查詢

最後還有一段理論。 媒體查詢可讓作者測試及查詢使用者代理程式或顯示裝置的值或功能,而不受算繪文件影響。在 CSS @media 規則中,這些參數可以有條件地將樣式套用至文件,以及 HTML 和 JavaScript 等其他各種內容和語言。媒體查詢層級 5 提供了所謂的使用者偏好設定媒體功能,可讓網站偵測使用者偏好的內容顯示方式。

prefers-color-scheme 媒體功能會用來偵測使用者是否要求網頁使用淺色或深色主題。這個函式可搭配下列值使用:

  • light:表示使用者已告知系統,他們想使用淺色主題的網頁 (淺色背景搭配深色文字)。
  • dark:表示使用者已告知系統,他們想使用使用深色主題 (淺色文字為深色背景) 的網頁。

支援深色模式

瞭解瀏覽器是否支援深色模式

由於深色模式是透過媒體查詢回報,因此只要檢查媒體查詢 prefers-color-scheme 是否相符,即可輕鬆確認目前的瀏覽器是否支援深色模式。請注意,我不會加入任何值,但單純檢查媒體查詢是否相符。

if (window.matchMedia('(prefers-color-scheme)').media !== 'not all') {
  console.log('🎉 Dark mode is supported');
}

撰寫本文件時,自 Chrome 和 Edge 起,prefers-color-scheme適用於電腦和行動裝置 (如適用)如果您是使用其他瀏覽器,則可參閱我可以使用支援資料表

在要求時瞭解使用者的偏好

透過 Sec-CH-Prefers-Color-Scheme 用戶端提示標頭,網站可在要求時選擇性地取得使用者的色彩配置偏好設定,讓伺服器內嵌正確的 CSS,避免閃爍錯誤的色彩主題。

深色模式實務

最後來看看支援深色模式的實際運作情形。和高地人一樣,深色模式只能擇一:深色或淺色,但絕不兩者皆是!為何提到這點?因為這會影響載入策略。如果使用者目前未使用重要算繪路徑,請勿強制要求使用者下載 CSS。 因此,為了盡可能加快載入速度,我將範例應用程式的 CSS 分成三個部分,並在其中將採行下列建議的做法分成三個部分,藉此延遲不重要的 CSS

  • style.css,包含網站上通用的一般規則。
  • dark.css,僅包含深色模式所需的規則。
  • light.css,僅包含淺色模式所需的規則。

載入策略

後者 (light.cssdark.css) 會根據 <link media> 查詢有條件地載入。起初,並非所有瀏覽器都支援 prefers-color-scheme (請使用上述模式偵測),我則可以透過減去內嵌指令碼有條件插入預設的 light.css 檔案,以動態方式處理預設的 light.css 檔案 (淺色是任意選項,我也可以將備用介面設為深色)。<link rel="stylesheet">為了避免閃爍未設定樣式的內容,我會在 light.css 載入前隱藏頁面內容。

<script>
  // If `prefers-color-scheme` is not supported, fall back to light mode.
  // In this case, light.css will be downloaded with `highest` priority.
  if (window.matchMedia('(prefers-color-scheme: dark)').media === 'not all') {
    document.documentElement.style.display = 'none';
    document.head.insertAdjacentHTML(
      'beforeend',
      '<link rel="stylesheet" href="/light.css" onload="document.documentElement.style.display = \'\'">',
    );
  }
</script>
<!--
  Conditionally either load the light or the dark stylesheet. The matching file
  will be downloaded with `highest`, the non-matching file with `lowest`
  priority. If the browser doesn't support `prefers-color-scheme`, the media
  query is unknown and the files are downloaded with `lowest` priority (but
  above I already force `highest` priority for my default light experience).
-->
<link rel="stylesheet" href="/dark.css" media="(prefers-color-scheme: dark)" />
<link
  rel="stylesheet"
  href="/light.css"
  media="(prefers-color-scheme: light)"
/>
<!-- The main stylesheet -->
<link rel="stylesheet" href="/style.css" />

樣式表架構

但盡量使用 CSS 變數,這樣我的一般 style.css 內容就會更豐富、一般,而且所有淺色或深色模式自訂作業都是在另外兩個檔案 dark.csslight.css 中進行。下方提供實際樣式的摘錄,但應該足以傳達整體概念。 我宣告了兩個變數 (-⁠-⁠color-⁠-⁠background-color),基本上會建立深色淺色 (深色) 基準主題。

/* light.css: 👉 dark-on-light */
:root {
  --color: rgb(5, 5, 5);
  --background-color: rgb(250, 250, 250);
}
/* dark.css: 👉 light-on-dark */
:root {
  --color: rgb(250, 250, 250);
  --background-color: rgb(5, 5, 5);
}

接著在 style.css 中,在 body { … } 規則中使用這些變數。 如同 :root CSS 虛擬類別所定義,HTML 中的選取器代表 <html> 元素,且與選取器 html 相同,差別只在於其特有性較高,可讓我宣告全域 CSS 變數。

/* style.css */
:root {
  color-scheme: light dark;
}

body {
  color: var(--color);
  background-color: var(--background-color);
}

在上方的程式碼範例中,您可能已經注意到 color-scheme 屬性以空格分隔的值 light dark

這可讓瀏覽器瞭解我的應用程式支援哪些顏色主題,並允許瀏覽器啟用使用者代理程式樣式表的特殊變化版本,例如讓瀏覽器顯示深色背景和淺色文字的表單欄位、調整捲軸,或啟用主題感知的醒目顯示顏色。CSS 色彩調整模組層級 1 中已指定 color-scheme 的確切詳細資料。

接下來,只需針對網站上重要的項目定義 CSS 變數即可。使用深色模式時,語意整理樣式可大幅改善。舉例來說,請考慮呼叫變數 -⁠-⁠accent-color,而不要呼叫 -⁠-⁠highlight-yellow,因為在深色模式中,「黃色」實際上可能不是黃色,反之亦然。以下範例是我在範例中使用的其他變數。

/* dark.css */
:root {
  --color: rgb(250, 250, 250);
  --background-color: rgb(5, 5, 5);
  --link-color: rgb(0, 188, 212);
  --main-headline-color: rgb(233, 30, 99);
  --accent-background-color: rgb(0, 188, 212);
  --accent-color: rgb(5, 5, 5);
}
/* light.css */
:root {
  --color: rgb(5, 5, 5);
  --background-color: rgb(250, 250, 250);
  --link-color: rgb(0, 0, 238);
  --main-headline-color: rgb(0, 0, 192);
  --accent-background-color: rgb(0, 0, 238);
  --accent-color: rgb(250, 250, 250);
}

完整範例

在下方 Glitch 中,您可以看到將上述概念實際應用的完整範例。請試著在特定的作業系統設定中切換深色模式,看看頁面的回應情形。

載入影響

播放這個範例時,您可以看到透過媒體查詢載入 dark.csslight.css 的原因。請嘗試切換深色模式並重新載入頁面:仍會載入目前不相符的樣式表,但優先順序最低,因此不會與網站目前所需的資源競爭。

顯示淺色模式的網路載入圖表,如何載入深色模式 CSS 以最低優先順序載入
採用淺色模式的網站會載入優先順序最低的深色模式 CSS。
網路載入圖表,顯示淺色模式 CSS 在載入時,優先順序最低
採用深色模式的網站會以最低的優先順序載入淺色模式 CSS。
網路載入圖表,顯示在預設淺色模式中,載入深色模式 CSS 時,系統如何以最低優先順序載入 CSS
在不支援 prefers-color-scheme 的瀏覽器上,採用預設淺色模式的網站會載入最低優先順序的深色模式 CSS。

根據深色模式的變更做出回應

如同任何其他媒體查詢變更,您可以透過 JavaScript 訂閱深色模式的變更。舉例來說,您可以使用這項功能動態變更網頁的網站小圖示,或變更用來決定 Chrome 網址列顏色的 <meta name="theme-color">。上方完整範例示範了實際運作情形,如要查看主題顏色和網站小圖示的變化,請在另一個分頁中開啟示範

const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
darkModeMediaQuery.addEventListener('change', (e) => {
  const darkModeOn = e.matches;
  console.log(`Dark mode is ${darkModeOn ? '🌒 on' : '☀️ off'}.`);
});

自 Chromium 93 和 Safari 15 起,您可以使用 meta 主題色彩元素的 media 屬性,根據媒體查詢調整顏色。系統會挑選第一個相符的項目。舉例來說,淺色模式和深色模式分別可以有一種顏色。撰寫時,您無法在資訊清單中定義這些項目。請參閱 w3c/manifest#975 GitHub 問題

<meta
  name="theme-color"
  media="(prefers-color-scheme: light)"
  content="white"
/>
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="black" />

偵錯及測試深色模式

在開發人員工具中模擬 prefers-color-scheme

切換整個作業系統的色彩配置可能會快速產生惱人的問題,因此 Chrome 開發人員工具現在可讓您以只會影響目前顯示分頁的方式,模擬使用者偏好的色彩配置。開啟「指令選單」,開始輸入 Rendering 並執行 Show Rendering 指令,然後變更「Emulate CSS media featurepreferreds-color-scheme」選項。

Chrome 開發人員工具「轉譯」分頁中的「Emulate CSS media 功能 preferencess-color-scheme」選項螢幕截圖

正在使用 Puppeteer 拍攝 prefers-color-scheme 的螢幕截圖

Puppeteer 是一個 Node.js 程式庫,可提供高階 API,用來透過開發人員工具通訊協定控制 Chrome 或 Chromium。我們提供 dark-mode-screenshot 的 Puppeteer 指令碼,可用來在深色和淺色模式中建立頁面螢幕截圖。 您可以將這個指令碼當做一次性執行,也可以將其加入持續整合 (CI) 測試套件中。

npx dark-mode-screenshot --url https://googlechromelabs.github.io/dark-mode-toggle/demo/ --output screenshot --fullPage --pause 750

深色模式最佳做法

避免使用純白色

您可能已註意到,我沒有使用純白色。 我之所以選擇稍微深色的白色,是為了避免在周圍黑暗的內容中發光和出血。類似 rgb(250, 250, 250) 的工具都能順利運作。

重新上色及調暗攝影圖片

如果比較以下兩張螢幕截圖,您會發現不僅核心主題已從「dark-on-light」變更為「light-on-dark」,而主頁橫幅看起來也稍有不同。我的使用者研究顯示,在啟用深色模式的情況下,大多數受訪人士偏好較鮮少且鮮豔的圖片。我們稱之為「重新著色」

在深色模式中,主頁橫幅稍微變暗。
在深色模式下,主頁橫幅稍微變暗。
淺色模式的一般主頁橫幅。
淺色模式的一般主頁橫幅。

可以透過 CSS 濾鏡將我的圖片重新上色。我使用的 CSS 選取器比對網址不含 .svg 的所有圖片,這個構想就是讓向量圖形 (圖示) 重新設定顏色的方式,與圖片 (相片) 不同。如需詳情,請查看下一段。請注意,我要再次使用 CSS 變數,以便之後靈活變更篩選器。

由於只有在深色模式下才需要重新著色,也就是說,當 dark.css 啟用時,light.css 中沒有對應規則。

/* dark.css */
--image-filter: grayscale(50%);

img:not([src*='.svg']) {
  filter: var(--image-filter);
}

使用 JavaScript 自訂深色模式重新著色效果

每個人的需求不盡相同,深色模式的需求也不盡相同。 您只要繼續使用上述的重新著色方法,就能輕鬆透過 JavaScript 變更的灰階強度;如果將值設為 0%,我也可以完全停用重新著色功能。請注意,document.documentElement 會提供文件根元素的參照,也就是我可以使用 :root CSS 虛擬類別參照的相同元素。

const filter = 'grayscale(70%)';
document.documentElement.style.setProperty('--image-filter', value);

反轉向量圖形和圖示

針對向量圖形 (在本例中為透過 <img> 元素參照的圖示),我使用不同的重新著色方法。雖然研究顯示人們不喜歡相片反轉,但對於大多數圖示而言,這項功能都能順利運作。再次使用 CSS 變數來判斷一般和 :hover 狀態的反轉數量。

在深色模式中,圖示會反轉。
在深色模式下,圖示會反轉。
淺色模式中的一般圖示。
淺色模式下的一般圖示。

再次注意,我只會反轉 dark.css 中的圖示,而不反轉 light.css 中的圖示,以及 :hover 在兩種情況下會如何呈現不同的反轉強度,讓圖示稍微變暗或更亮,實際情況視使用者選取的模式而定。

/* dark.css */
--icon-filter: invert(100%);
--icon-filter_hover: invert(40%);

img[src*='.svg'] {
  filter: var(--icon-filter);
}
/* light.css */
--icon-filter_hover: invert(60%);
/* style.css */
img[src*='.svg']:hover {
  filter: var(--icon-filter_hover);
}

針對內嵌 SVG 使用 currentColor

如果是內嵌可擴充向量圖形圖片,您不必使用反轉濾鏡,您可以使用代表元素 color 屬性值的 currentColor CSS 關鍵字。這可讓您在預設不會接收值的屬性上使用 color 值。簡單來說,如果 currentColor 做為 SVG fillstroke 屬性的值使用,則會從顏色屬性值沿用而來的值。更棒的是,這也適用於 <svg><use href="…"></svg>,因此您可以擁有個別的資源,並將 currentColor 套用在結構定義中。請注意,這僅適用於內嵌<use href="…"> SVG,但不適用於以圖片 src 參照的 SVG,或透過 CSS 進行某種方式的 SVG。 您可以在下方的示範中看到這項套用建議。

<!-- Some inline SVG -->
<svg xmlns="http://www.w3.org/2000/svg"
    stroke="currentColor"
>
  […]
</svg>

在不同的模式之間順暢轉換

從深色模式切換為淺色模式 (或從深色模式切換為淺色模式) 可非常順暢,因為 colorbackground-color 皆為可模擬的 CSS 屬性。建立動畫就像為兩個屬性宣告兩個 transition 一樣簡單。以下範例說明整個概念,您可以在示範中實際體驗。

body {
  --duration: 0.5s;
  --timing: ease;

  color: var(--color);
  background-color: var(--background-color);

  transition: color var(--duration) var(--timing), background-color var(
        --duration
      ) var(--timing);
}

使用深色模式的藝術方向

基於載入效能的考量,一般而言,建議您僅使用 <link> 元素的 media 屬性中的 prefers-color-scheme (而不是在樣式表中嵌入),但在某些情況下,建議您直接在 HTML 程式碼中直接使用 prefers-color-scheme。這時藝術方針就屬於這種情況。在網路上,美術方向著重在網頁的整體視覺外觀,以及網頁如何傳達訊息的視覺傳達、刺激感和對比元素,以及對目標對象的心理吸引力。

使用深色模式時,設計人員可自行判斷在特定模式中最適合的圖片,以及重新調色圖片是否「不夠」足夠。 如果與 <picture> 元素搭配使用,要顯示的圖片 <source> 可視 media 屬性而定。在以下範例中,我顯示了西半球的深色模式、淺色模式或未指定時的東半球,在其他情況下則預設為東半球。本課程僅供參考。在裝置上切換深色模式,即可看到不同之處。

<picture>
  <source srcset="western.webp" media="(prefers-color-scheme: dark)" />
  <source srcset="eastern.webp" media="(prefers-color-scheme: light)" />
  <img src="eastern.webp" />
</picture>

深色模式,但新增了停用功能

如上方「為什麼要使用深色模式」一節所述,大多數使用者都會選擇深色模式。因此,部分使用者可能想將作業系統 UI 設為深色,但仍偏好查看自己瀏覽網頁的方式。建議您一開始先遵循瀏覽器透過 prefers-color-scheme 傳送的信號,但接著可選擇允許使用者覆寫系統層級設定。

<dark-mode-toggle> 自訂元素

當然,您也可以自行建立程式碼,但也可以直接使用我為了這個目的而建立的現成自訂元素 (網頁元件)。名為 <dark-mode-toggle>,它會為網頁新增切換 (深色模式:開啟/關閉) 或主題切換器 (主題:淺色/深色),您可以完全自訂。下方示範元素展示了元素的實際運作情形 (沒錯,我也 🤫? 隱瞞了元素,所以全都可以放進上述其他 範例)。

<dark-mode-toggle
  legend="Theme Switcher"
  appearance="switch"
  dark="Dark"
  light="Light"
  remember="Remember this"
></dark-mode-toggle>
淺色模式中的深色模式切換鈕。
處於淺色模式的 <dark-mode-toggle>
淺色模式中的深色模式切換鈕。
<dark-mode-toggle> (深色模式)。

點選或輕觸下方示範右上角的深色模式控制項。 如果您勾選第三和第四個控制項的核取方塊,即使重新載入頁面時,系統還是會記住您的模式選項。如此一來,訪客就能保持作業系統採用深色模式,同時以淺色模式瀏覽網站,反之亦然。

結論

使用及支援深色模式相當有趣,且開啟了新的設計途徑。對某些訪客來說,無法處理自家網站和讓他們感到滿意的地方,可能有所不同。 並絕對需要嚴密的測試和嚴謹的測試,但如要展現重視所有使用者,深色模式絕對是絕佳的機會。本文所提及的最佳做法和 <dark-mode-toggle> 自訂元素等輔助工具,應讓您確信自己有能力打造出色的深色模式體驗。在 Twitter 上告訴我你的內容,以及這篇貼文是否實用,或知道如何改善貼文。 感謝閱讀!🌒

prefers-color-scheme 媒體查詢的資源:

color-scheme 中繼標記和 CSS 屬性相關資源:

一般深色模式連結:

本文的背景研究文章:

特別銘謝

prefers-color-scheme 媒體功能、color-scheme CSS 屬性和相關中繼標記是 👏? Rune Lillesveen 的實作工作。 Rune 也是 CSS 色彩調整項模組層級 1 規格的共同編輯。 🙏? 謝謝 Lukasz ZbylutRowan MerewoodChirag DesaiRob Dodson 的內容完整評論。 載入策略Jake Archibald 的腦部。Emilio Cobos Álvarez 向我說明正確的 prefers-color-scheme 偵測方法。參照 SVG 和 currentColor 的提示來自 Timothy Hatcher。最後,我感謝許多匿名參與者參與,這些研究有助於制定本文中推薦的相關內容。主頁橫幅由 Nathan Anderson 提供。