JavaScript中最好的明暗模式主題切換
我曾經不同意淺色和深色模式切換?!扒袚Q開關是用戶系統(tǒng)偏好設置!” 我會天真地感嘆,選擇讓prefers-color-scheme CSS媒體查詢控制我個人網站上的主題。沒有切換。沒有選擇。??
自從黑暗模式出現以來,我一直是它的用戶。但最近,我更喜歡在輕型模式下使用一些網站和工具 - 包括我的個人網站 - 同時將我的系統(tǒng)設置牢牢保持在黑暗中。我需要一個開關。我需要一個選擇!其他人也是如此。
在這篇文章中,我將向您展示如何使用 JavaScript 為我的網站構建終極主題 Toggle??:
在本地瀏覽器存儲中存儲和檢索主題首選項,
退回到用戶系統(tǒng)首選項,
如果未檢測到上述情況,則回退到默認主題。
TL;DR:這是 CodePen 上的代碼。
(更|多優(yōu)質內|容:java567 點 c0m)
將數據屬性添加到 HTML 標記
在 HTML 標記上,添加數據屬性(例如)data-theme,并為其指定默認值淺色或深色。過去我使用自定義屬性color-mode而不是數據屬性(例如color-mode="light")。雖然這有效,但它沒有被歸類為有效的 HTML,而且我找不到任何相關文檔!對此的任何見解都非常感激。??
?<html data-theme="light">
? ? ?<!-- all other HTML -->
?</html>
通過 CSS 自定義屬性配置主題
在 CSS 中,通過每個屬性值下的CSS 自定義屬性(或變量)配置主題顏色data-theme。請注意,您不一定需要:root與 結合使用data-theme,但它對于不隨主題更改的全局屬性很有用(如下例所示)。在 MDN 上了解有關 :root CSS 偽類的更多信息。
?:root {
? ?--grid-unit: 1rem;
? ?--border-radius-base: 0.5rem;
?}
?
?[data-theme="light"] {
? ?--color-bg: #ffffff;
? ?--color-fg: #000000;
?}
?
?[data-theme="dark"] {
? ?--color-bg: #000000;
? ?--color-fg: #ffffff;
?}
?
?/* example use of CSS custom properties */
?body {
? ?background-color: var(--color-bg);
? ?color: var(--color-fg);
?}
在 HTML 標記上手動切換data-theme屬性,您將看到主題已發(fā)生變化(只要您使用這些 CSS 屬性來設置元素的樣式)!
在 HTML 中構建切換按鈕
將 HTML 按鈕添加到您的網站標題或任何需要主題切換的位置。添加一個data-theme-toggle屬性(我們稍后將使用它來定位 JavaScript 中的按鈕),如果您打算在按鈕上使用圖標(例如太陽和月亮分別代表淺色和深色模式),則添加一個aria-label ,以便屏幕閱讀器和輔助技術可以理解交互按鈕的用途。
?<button
? ? ?type="button"
? ? ?data-theme-toggle
? ? ?aria-label="Change to light theme"
? ?>Change to light theme (or icon here)</button>
計算頁面加載時的主題設置
在這里,我們將根據我所說的“偏好級聯(lián)”來計算主題設置。
從本地存儲獲取主題首選項
我們可以使用JavaScript 中的 localStorage 屬性將用戶首選項保存在瀏覽器中,并在會話之間持續(xù)存在(或直到手動清除)。在 The Ultimate Theme Toggle?? 中,存儲的用戶首選項是最重要的設置,因此我們將首先查找它。
頁面加載時,用于localStorage.getItem("theme")檢查先前存儲的首選項。在本文后面,我們將在每次按下切換按鈕時更新主題值。如果沒有本地存儲值,則該值為null。
?// get theme on page load
?localStorage.getItem("theme");
?
?// set theme on button press
?localStorage.setItem("theme", newTheme);
在 JavaScript 中檢測用戶系統(tǒng)設置
如果 中沒有存儲的主題首選項,我們將使用window.matchMedia() 方法通過傳入媒體查詢字符串來localStorage檢測用戶的系統(tǒng)設置。您只需計算一項設置即可實現首選項級聯(lián),但下面的代碼顯示了如何檢測淺色或深色系統(tǒng)設置。
?const systemSettingDark = window.matchMedia("(prefers-color-scheme: dark)");
?// or
?const systemSettingLight = window.matchMedia("(prefers-color-scheme: light)");
window.matchMedia()返回一個MediaQueryList包含您請求的媒體查詢字符串,以及它是否matches(真/假)用戶系統(tǒng)設置。
?{
? ?matches: true,
? ?media: "(prefers-color-scheme: dark)",
? ?onchange: null
?}
回退到默認主題
現在您可以通過 訪問localStorage值和系統(tǒng)設置window.matchMedia(),您可以使用首選項級聯(lián)(本地存儲,然后系統(tǒng)設置)計算首選主題設置,并回退到您選擇的默認主題(這應該是您的默認主題)之前在您的 HTML 標記中指定)。
我們將在頁面加載時運行此代碼來計算當前的主題設置。
?function calculateSettingAsThemeString({ localStorageTheme, systemSettingDark }) {
? ?if (localStorageTheme !== null) {
? ? ?return localStorageTheme;
? ?}
?
? ?if (systemSettingDark.matches) {
? ? ?return "dark";
? ?}
?
? ?return "light";
?}
?
?const localStorageTheme = localStorage.getItem("theme");
?const systemSettingDark = window.matchMedia("(prefers-color-scheme: dark)");
?
?let currentThemeSetting = calculateSettingAsThemeString({ localStorageTheme, systemSettingDark });
向切換按鈕添加事件偵聽器
接下來,我們將設置一個事件偵聽器,以便在按下按鈕時切換主題。使用我們之前添加的數據屬性 ( ) 將按鈕定位到 DOM 中data-theme-toggle,并在單擊時向按鈕添加事件偵聽器。下面的示例非常冗長,您可能希望將下面的一些功能抽象為實用函數(我在CodePen 的示例中已完成)。讓我們來看看:
將新主題計算為字符串
計算并更新按鈕文本(如果您在按鈕上使用圖標,則可以在此處進行切換)
更新按鈕上的 aria-label
切換 HTML 標簽上的 data-theme 屬性
將新的主題首選項保存在本地存儲中
更新內存中的currentThemeSetting
?// target the button using the data attribute we added earlier
?const button = document.querySelector("[data-theme-toggle]");
?
?button.addEventListener("click", () => {
? ?const newTheme = currentThemeSetting === "dark" ? "light" : "dark";
?
? ?// update the button text
? ?const newCta = newTheme === "dark" ? "Change to light theme" : "Change to dark theme";
? ?button.innerText = newCta; ?
?
? ?// use an aria-label if you are omitting text on the button
? ?// and using sun/moon icons, for example
? ?button.setAttribute("aria-label", newCta);
?
? ?// update theme attribute on HTML to switch theme in CSS
? ?document.querySelector("html").setAttribute("data-theme", newTheme);
?
? ?// update in local storage
? ?localStorage.setItem("theme", newTheme);
?
? ?// update the currentThemeSetting in memory
? ?currentThemeSetting = newTheme;
?});
要確認localStorage正在更新,請打開開發(fā)工具,導航到選項Application卡,展開Local Storage并選擇您的站點。你會看到一個鍵:值列表;查找theme并單擊按鈕即可觀看其實時更新。重新加載您的頁面,您將看到保留的主題首選項!
把它們放在一起!
您現在可以通過以下方式構建您自己的終極主題切換??:
使用 CSS 自定義屬性來指定不同的主題顏色,通過 HTML 標記上的數據屬性進行切換
使用 HTML 按鈕來啟動切換
使用首選項級聯(lián)計算頁面加載時的首選主題(本地存儲 > 系統(tǒng)設置 > 后備默認主題)
單擊切換按鈕即可切換主題,并將用戶首選項存儲在瀏覽器中以供將來訪問
這是完整的 CodePen,您可以在我的個人網站上查看工作版本??鞓非袚Q!