我曾經不同意淺色和深色模式切換。 “切換開關是用戶系統偏好設置!”我會天真地感嘆,選擇讓 prefers-color-scheme CSS 媒體查詢 控制我個人網站上的主題。沒有切換。沒有選擇。 🫠
自從黑暗模式出現以來,我一直是它的用戶。但最近,我更喜歡在輕型模式下使用_一些_網站和工具 - 包括我的個人網站 - 同時將我的系統設置牢牢地保留在黑暗中。我需要一個開關。我需要一個選擇!其他人也是如此。
在這篇文章中,我將向您展示如何使用 JavaScript 為我的網站建置終極主題 Toggle™️:
在本地瀏覽器存儲中存儲和檢索主題首選項,
退回到用戶系統首選項,
如果未檢測到上述情況,則回退到默認主題。
TL;DR:這是 CodePen 上的程式碼。
原文出處:https://dev.to/whitep4nth3r/the-best-lightdark-mode-theme-toggle-in-javascript-368f
在 HTML 標記上,加入一個資料屬性,例如“data-theme”,並為其指定默認值“淺色”或“深色”。過去我使用自定義屬性“color-mode”而不是資料屬性(例如“color-mode=”light“”)。雖然這可行,但它沒有被歸類為有效的 HTML,而且我找不到任何相關文件!對此的任何見解都非常感激。 😅
<html lang="en" data-theme="light">
<!-- all other HTML -->
</html>
在 CSS 中,通過“data-theme”每個值下的 CSS 自定義屬性(或變數)配置主題顏色屬性。請注意,您不一定需要將
: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”屬性,您就會看到主題已經發生變化(只要您使用這些 CSS 屬性來設置元素的樣式)!
將 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>
在這裡,我們將根據我所說的“偏好級聯”來計算主題設置。
我們可以使用 JavaScript 中的 localStorage 屬性 將用戶首選項保存在瀏覽器中,該首選項在會話之間持續存在(或直到它手動清除)。在 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);
如果“localStorage”中沒有存儲的主題首選項,我們將使用 window.matchMedia() 方法通過傳入媒體查詢字串。您只需計算一項設置即可實現首選項級聯,但下面的程式碼顯示瞭如何檢測淺色或深色系統設置。
const systemSettingDark = window.matchMedia("(prefers-color-scheme: dark)");
// or
const systemSettingLight = window.matchMedia("(prefers-color-scheme: light)");
window.matchMedia()
返回一個 MediaQueryList
,其中包含您請求的媒體查詢字串,以及它是否與用戶系統設置“匹配”(true/false)。
{
matches: true,
media: "(prefers-color-scheme: dark)",
onchange: null
}
現在您可以通過“window.matchMedia()”存取“localStorage”值和系統設置,您可以使用首選項級聯(本地存儲,然後系統設置)計算首選主題設置,並回退到默認主題您的選擇(這應該是您之前在 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 });
接下來,我們將設置一個事件監聽器,以便在按下按鈕時切換主題。使用我們之前加入的資料屬性(data-theme-toggle
)定位 DOM 中的按鈕,並加入一個事件監聽器 加入到單擊按鈕。
// 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”正在更新,請打開開發工具,導航到“Application”選項卡,展開“Local Storage”並選擇您的站點。你會看到一個鍵:值列表;查找“主題”並單擊按鈕即可觀看其實時更新。重新加載您的頁面,您將看到保留的主題首選項!
您現在可以通過以下方式建置您自己的終極主題切換™️:
這是完整的 CodePen,您可以在我的個人網站上查看工作版本。快樂切換!