我曾經不同意淺色和深色模式切換。 “切換開關是用戶系統偏好設置!”我會天真地感嘆,選擇讓 prefers-color-scheme CSS 媒體查詢 控制我個人網站上的主題。沒有切換。沒有選擇。 🫠

自從黑暗模式出現以來,我一直是它的用戶。但最近,我更喜歡在輕型模式下使用一些網站和工具 - 包括我的個人網站 - 同時將我的系統設置牢牢地保留在黑暗中。我需要一個開關。我需要一個選擇!其他人也是如此。

在這篇文章中,我將向您展示如何使用 JavaScript 為我的網站建置終極主題 Toggle™️:

  1. 在本地瀏覽器存儲中存儲和檢索主題首選項,

  2. 退回到用戶系統首選項,

  3. 如果未檢測到上述情況,則回退到默認主題。

TL;DR:這是 CodePen 上的程式碼

原文出處:https://dev.to/whitep4nth3r/the-best-lightdark-mode-theme-toggle-in-javascript-368f

將資料屬性加入到 HTML 標記中

在 HTML 標記上,加入一個資料屬性,例如“data-theme”,並為其指定默認值“淺色”或“深色”。過去我使用自定義屬性“color-mode”而不是資料屬性(例如“color-mode=”light“”)。雖然這可行,但它沒有被歸類為有效的 HTML,而且我找不到任何相關文件!對此的任何見解都非常感激。 😅

<html lang="en" data-theme="light">
    <!-- all other HTML -->
</html>

通過 CSS 自定義屬性配置主題

在 CSS 中,通過“data-theme”每個值下的 CSS 自定義屬性(或變數)配置主題顏色屬性。請注意,您不一定需要將:rootdata-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 中建置一個切換按鈕

將 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);

在 JavaScript 中檢測用戶系統設置

如果“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 中的按鈕,並加入一個事件監聽器 加入到單擊按鈕。

  • 將新主題計算為字串
  • 計算並更新按鈕文本(如果您在按鈕上使用圖標,則可以在此處進行切換)
  • 更新按鈕上的aria標籤
  • 切換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”正在更新,請打開開發工具,導航到“Application”選項卡,展開“Local Storage”並選擇您的站點。你會看到一個鍵:值列表;查找“主題”並單擊按鈕即可觀看其實時更新。重新加載您的頁面,您將看到保留的主題首選項!

帶有開發工具的瀏覽器窗口在應用程式選項卡上打開。選擇whitepanther dot com上的本地存儲,顯示主題light瀏覽器中存儲的鍵值對。

把它們放在一起!

您現在可以通過以下方式建置您自己的終極主題切換™️:

  • 使用CSS自定義屬性來指定不同的主題顏色,通過HTML標籤上的資料屬性進行切換
  • 使用 HTML 按鈕來啟動切換
  • 使用首選項級聯計算頁面加載時的首選主題(本地存儲 > 系統設置 > 後備默認主題)
  • 單擊切換按鈕即可切換主題,並將用戶首選項存儲在瀏覽器中以供將來存取

這是完整的 CodePen,您可以在我的個人網站上查看工作版本。快樂切換!

https://codepen.io/whitep4nth3r/pen/VwEqrQL


共有 0 則留言