JavaScript中最好的明暗模式主题切换
我曾经不同意浅色和深色模式切换。“切换开关是用户系统偏好设置!” 我会天真地感叹,选择让prefers-color-scheme CSS媒体查询控制我个人网站上的主题。没有切换。没有选择。🫠
自从黑暗模式出现以来,我一直是它的用户。但最近,我更喜欢在轻型模式下使用一些网站和工具 - 包括我的个人网站 - 同时将我的系统设置牢牢保持在黑暗中。我需要一个开关。我需要一个选择!其他人也是如此。
在这篇文章中,我将向您展示如何使用 JavaScript 为我的网站构建终极主题 Toggle™️:
在本地浏览器存储中存储和检索主题首选项,
退回到用户系统首选项,
如果未检测到上述情况,则回退到默认主题。
TL;DR:这是 CodePen 上的代码。
(更|多优质内|容: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属性,您将看到主题已发生变化(只要您使用这些 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 的示例中已完成)。让我们来看看:
将新主题计算为字符串
计算并更新按钮文本(如果您在按钮上使用图标,则可以在此处进行切换)
更新按钮上的 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正在更新,请打开开发工具,导航到选项Application卡,展开Local Storage并选择您的站点。你会看到一个键:值列表;查找theme并单击按钮即可观看其实时更新。重新加载您的页面,您将看到保留的主题首选项!
把它们放在一起!
您现在可以通过以下方式构建您自己的终极主题切换™️:
使用 CSS 自定义属性来指定不同的主题颜色,通过 HTML 标记上的数据属性进行切换
使用 HTML 按钮来启动切换
使用首选项级联计算页面加载时的首选主题(本地存储 > 系统设置 > 后备默认主题)
单击切换按钮即可切换主题,并将用户首选项存储在浏览器中以供将来访问
这是完整的 CodePen,您可以在我的个人网站上查看工作版本。快乐切换!