JavaScript中最好的明暗模式主题切换

发布时间 2023-06-25 10:12:52作者: 晓风晓浪

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


我曾经不同意浅色和深色模式切换。“切换开关是用户系统偏好设置!” 我会天真地感叹,选择让prefers-color-scheme CSS媒体查询控制我个人网站上的主题。没有切换。没有选择。?

自从黑暗模式出现以来,我一直是它的用户。但最近,我更喜欢在轻型模式下使用一些网站和工具 - 包括我的个人网站 - 同时将我的系统设置牢牢保持在黑暗中。我需要一个开关。我需要一个选择!其他人也是如此。

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

  1. 在本地浏览器存储中存储和检索主题首选项,

  2. 退回到用户系统首选项,

  3. 如果未检测到上述情况,则回退到默认主题。

TL;DR:这是 CodePen 上的代码。

(更|多优质内|容:java567 点 c0m)

 

将数据属性添加到 HTML 标记

在 HTML 标记上,添加数据属性(例如)data-theme,并为其指定默认值浅色或深色。过去我使用自定义属性color-mode而不是数据属性(例如color-mode="light")。虽然这有效,但它没有被归类为有效的 HTML,而且我找不到任何相关文档!对此的任何见解都非常感激。?

 <html lang="en" 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 {
 
  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 中检测用户系统设置

如果 中没有存储的主题首选项,我们将使用window.matchMedia() 方法通过传入媒体查询字符串来localStorage检测用户的系统设置。您只需计算一项设置即可实现首选项级联,但下面的代码显示了如何检测浅色或深色系统设置。

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

 

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

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

 

回退到默认主题

现在您可以通过 访问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 });

 

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

接下来,我们将设置一个事件侦听器,以便在按下按钮时切换主题。使用我们之前添加的数据属性 ( ) 将按钮定位到 DOM 中data-theme-toggle,并在单击时向按钮添加事件侦听器。下面的示例非常冗长,您可能希望将下面的一些功能抽象为实用函数(我在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;
 });

 

要确认localStorage正在更新,请打开开发工具,导航到选项Application卡,展开Local Storage并选择您的站点。你会看到一个键:值列表;查找theme并单击按钮即可观看其实时更新。重新加载您的页面,您将看到保留的主题首选项!

 

把它们放在一起!

您现在可以通过以下方式构建您自己的终极主题切换™️:

  1. 使用 CSS 自定义属性来指定不同的主题颜色,通过 HTML 标记上的数据属性进行切换

  2. 使用 HTML 按钮来启动切换

  3. 使用首选项级联计算页面加载时的首选主题(本地存储 > 系统设置 > 后备默认主题)

  4. 单击切换按钮即可切换主题,并将用户首选项存储在浏览器中以供将来访问

这是完整的 CodePen,您可以在我的个人网站上查看工作版本。快乐切换!

(更|多优质内|容:java567 点 c0m)