配色方案實作需要三個層次:
- 訪客尚未作出網站特定選擇時使用的系統偏好。
- 可以覆寫系統偏好的明確網站偏好。
- 讓元件不依賴字面淺色與深色值的語意色彩。
宣告語意色彩 #
依角色而不是外觀命名變數:
:root {
color-scheme: light dark;
--surface: #ffffff;
--surface-raised: #f5f6f8;
--text: #17191c;
--text-muted: #5d6470;
--border: #d7dbe0;
--accent: #1659b7;
}
body {
color: var(--text);
background: var(--surface);
}color-scheme 告訴使用者代理程式頁面支援哪些方案,使表單控制項、捲軸與系統色彩相符。它不會定義網站的自訂調色盤。
等效的早期提示可讓瀏覽器在樣式表送達前選擇合適的畫布色彩:
<meta name="color-scheme" content="light dark">根據系統偏好套用深色調色盤:
@media (prefers-color-scheme: dark) {
:root {
--surface: #17191c;
--surface-raised: #22262b;
--text: #eef0f2;
--text-muted: #b5bbc3;
--border: #3a4048;
--accent: #8ab4f8;
}
}不應使用已過時的 no-preference 值。
定義明確的覆寫優先順序 #
將訪客的明確選擇儲存為 light、dark 或 system。根元素上的屬性可以覆寫媒體查詢:
:root[data-theme="light"] {
color-scheme: light;
--surface: #ffffff;
--surface-raised: #f5f6f8;
--text: #17191c;
--text-muted: #5d6470;
--border: #d7dbe0;
--accent: #1659b7;
}
:root[data-theme="dark"] {
color-scheme: dark;
--surface: #17191c;
--surface-raised: #22262b;
--text: #eef0f2;
--text-muted: #b5bbc3;
--border: #3a4048;
--accent: #8ab4f8;
}JavaScript 狀態轉換保持簡短:
function setTheme(theme) {
const root = document.documentElement;
if (theme === "system") {
delete root.dataset.theme;
localStorage.removeItem("theme");
return;
}
root.dataset.theme = theme;
localStorage.setItem("theme", theme);
}由於 local storage 可以變更,指派前要限制儲存值:
const saved = localStorage.getItem("theme");
if (saved === "light" || saved === "dark") {
document.documentElement.dataset.theme = saved;
}在文件 head 或內嵌啟動腳本中執行初始化,並在 body 呈現前完成。太晚套用可能短暫顯示錯誤調色盤。具有嚴格內容安全政策的網站可以使用 nonce,或根據已驗證 Cookie 在伺服器端產生根屬性。
回應系統變更 #
當 CSS 媒體查詢控制系統模式時,不需要監聽器。只有在應用程式狀態或畫布必須回應時,JavaScript 才需要監聽器:
const query = matchMedia("(prefers-color-scheme: dark)");
query.addEventListener("change", ({ matches }) => {
if (!document.documentElement.dataset.theme) {
redrawCanvas(matches ? "dark" : "light");
}
});明確的網站偏好不應被之後的作業系統變更覆寫。
為嵌入文件設定主題 #
內嵌 SVG 會參與父文件的級聯。透過 <img> 載入的 SVG 與透過 <iframe> 載入的文件具有獨立樣式樹,因此父文件自訂屬性不會跨越這些邊界。
嵌入元素使用的 color-scheme 可以影響嵌入文件的畫布與其 prefers-color-scheme 結果,但不會注入父文件撰寫的調色盤。對於應用程式控制的主題,請為同一應用程式的框架使用資源變體或刻意設計的 postMessage 協定。套用任何狀態前,先驗證訊息來源。
保留對比與意義 #
深色模式不是機械式反轉。請驗證:
- 文字與互動控制項對比。
- 兩種方案中的焦點指示器。
- 不單靠不透明度表示的停用與柔和狀態。
- 除色相外也使用標籤或形狀的圖表與狀態色彩。
- 影像、陰影、語法醒目提示與原生表單控制項。
使用語意變數,讓對比修正可以在整個網站變更同一角色。另行測試強制色彩模式,因為使用者代理程式色彩可能取代撰寫的調色盤,並移除框線陰影等效果:
@media (forced-colors: active) {
.focusable {
border: 1px solid transparent;
}
}在此模式中使用系統色彩與非色彩提示。只有對色彩本身承載必要資訊的內容(例如色票),才使用 forced-color-adjust: none,因為這會使元素退出使用者的對比替換。
評論
在 GitHub 上閱讀或評論(發表評論需要登入)