JavaScript 中最佳的亮/暗模式主题切换

2025-05-28

JavaScript 中最佳的亮/暗模式主题切换

学习如何使用 JavaScript、CSS 自定义属性、本地存储和系统设置,为您的网站构建终极主题切换™️。无需任何框架!


我以前很不赞同明暗模式的切换。“切换按钮就是用户系统偏好设置!”我会天真地喊道,然后选择让prefers-color-scheme CSS 媒体查询控制我个人网站的主题。没有切换按钮,别无选择。🫠

自从黑暗模式流行起来以来,我就一直是它的用户。但最近,我更喜欢在浅色模式下使用一些网站和工具——包括我的个人网站——同时将我的系统设置牢牢地保持在黑暗模式。我需要一个切换开关。我需要一个选择!其他人也一样。

在这篇文章中,我将向您展示如何使用 JavaScript 为我的网站构建 The Ultimate Theme Toggle™️:

  1. 在本地浏览器存储中存储和检索主题偏好设置,
  2. 恢复用户系统偏好设置,
  3. 如果未检测到以上任何内容,则恢复为默认主题。

TL;DR:这是 CodePen 上的代码

向 HTML 标签添加数据属性

在你的 HTML 标签上,添加一个数据属性,例如 ,data-theme并赋予其默认值“亮”或“暗”。过去我使用过自定义属性color-mode而不是数据属性(例如color-mode="light")。虽然这种方法有效,但它不属于有效的 HTML,而且我找不到任何相关文档!非常感谢任何关于这方面的见解。😅

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

通过 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);
}
Enter fullscreen mode Exit fullscreen mode

在 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>
Enter fullscreen mode Exit fullscreen mode

页面加载时计算主题设置

在这里,我们将根据我所说的“偏好级联”来计算主题设置。

从本地存储获取主题偏好

我们可以使用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);
Enter fullscreen mode Exit fullscreen mode

使用 JavaScript 检测用户系统设置

如果 中没有存储主题偏好设置,我们将使用window.matchMedia() 方法localStorage通过传入媒体查询字符串来检测用户的系统设置。您只需为偏好设置级联计算一项设置,但以下代码展示了如何检测亮色或暗色系统设置。

const systemSettingDark = window.matchMedia("(prefers-color-scheme: dark)");
// or
const systemSettingLight = window.matchMedia("(prefers-color-scheme: light)");
Enter fullscreen mode Exit fullscreen mode

window.matchMedia()返回一个MediaQueryList包含您请求的媒体查询字符串,以及它是否matches(true/false)用户系统设置。

{
  matches: true,
  media: "(prefers-color-scheme: dark)",
  onchange: null
}
Enter fullscreen mode Exit fullscreen mode

恢复默认主题

现在您可以通过访问localStorage值和系统设置window.matchMedia(),您可以使用首选项级联(本地存储,然后是系统设置)计算首选主题设置,并恢复到您选择的默认主题(应该是您之前在 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 });
Enter fullscreen mode Exit fullscreen mode

向切换按钮添加事件监听器

接下来,我们将设置一个事件监听器,以便在按钮按下时切换主题。使用data-theme-toggle我们之前添加的 data 属性 ( ) 在 DOM 中定位按钮,并在点击时为按钮添加一个事件监听器。下面的示例相当冗长,你可能需要将下面的一些功能抽象成实用函数(我在CodePen 上的示例中已经这样做了)。让我们来演示一下:

  1. 将新主题计算为字符串
  2. 计算并更新按钮文本(如果您在按钮上使用图标,则可以在此处进行切换)
  3. 更新按钮上的 aria-label
  4. 切换 HTML 标签上的 data-theme 属性
  5. 将新的主题偏好设置保存在本地存储中
  6. 更新内存中的 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;
});
Enter fullscreen mode Exit fullscreen mode

要确认localStorage正在更新,请打开您的开发工具,导航至Application相应标签页,展开Local Storage并选择您的网站。您将看到一个键值列表;找到theme并点击按钮即可实时查看更新。刷新页面,您将看到主题偏好设置已保存!

浏览器窗口,其中的“应用程序”选项卡上打开了开发工具。选中了 whitepanther.com 上的本地存储,显示了主题 light 浏览器中存储的键值对。

把它们放在一起!

您现在可以通过以下方式构建您自己的 Ultimate Theme Toggle™️:

  1. 使用 CSS 自定义属性指定不同的主题颜色,通过 HTML 标签上的数据属性切换
  2. 使用 HTML 按钮来切换
  3. 使用偏好级联(本地存储 > 系统设置 > 后备默认主题)计算页面加载时的首选主题
  4. 单击切换按钮即可切换主题,并将用户偏好存储在浏览器中以供将来访问

这是完整的 CodePen,你可以在我的个人网站上查看实际运行版本。祝你使用愉快!

文章来源:https://dev.to/whitep4nth3r/the-best-lightdark-mode-theme-toggle-in-javascript-368f
PREV
我创建了一个可以帮我和招聘人员沟通的机器人(它真的太棒了!)什么对我来说很重要?收到这样的工作邀请有什么好处?
NEXT
图表是终极工程工具