搜索
首页web前端css教程在几分钟内构建一个黑暗模式切换(实际上有效)

Build a Dark Mode Toggle in inutes (That Actually Works)

是否曾经花费数小时实现黑暗模式切换,却在页面刷新时闪烁着令人眼花缭乱的白色?或者更糟糕的是,它是否完全忽略了用户的系统偏好?是的,我也是。 ?

事情是这样的 - 黑暗模式不再只是一个流行的功能。随着越来越多的人在夜间编码(被指控有罪)和可访问性变得越来越重要,实施良好的黑暗模式实际上是现代网站或网络应用程序的必备条件。但要做好它可能会非常棘手。

好消息?在摸索各种实现并与 localStorage 进行斗争之后,我终于破解了黑暗模式切换的代码:

  • 实际上记住你的用户的偏好
  • 重新加载时不会闪烁错误的主题
  • 与系统偏好设置配合得很好
  • 实施只需 5 分钟

在这篇文章中,我将引导您构建一个您真正想要使用的黑暗模式切换开关。没有过于复杂的解决方案,没有不必要的依赖项 - 只有干净、可以立即实现的工作代码。

先决条件(你需要的东西)

让我们先把无聊的部分抛开 - 但我保证保持简短!

您可能已经拥有所需的一切,但只是为了确保我们达成共识:

  • 基本 HTML(例如,你知道
  • 一些 CSS 知识(尤其是 CSS 变量 - 但我会边做边解释)
  • Vanilla JavaScript(没什么花哨的,我保证)
  • 您最喜欢的代码编辑器
  • 大约 5 分钟的时间(也许还有一杯咖啡☕)

我们正在建设什么

在我们开始之前,先快速浏览一下我们最终会得到什么。没有花哨的 UI 库或复杂的设置 - 只是一个简单、流畅的切换,如下所示:

不要担心让它看起来像这样 - 重要的是它会完美地工作。我们将首先关注功能,然后您可以根据需要设计它的样式。

最好的部分?我们要构建的所有内容都适用于:

  • 现代浏览器(是的,甚至是 Safari!)
  • 系统深色模式偏好设置
  • 页面刷新(不再出现白屏闪烁)
  • 零外部依赖

准备好动手了吗?让我们从基础开始吧!

建立基金会

好吧,让我们动手吧!首先,我们将建立基本结构。

HTML:保持简单

我们将从一些极其简单的 HTML 开始。这部分不用想太多:

<button>



<h3>
  
  
  The CSS
</h3>

<p>Here's where things get interesting. We'll use CSS variables (aka custom properties) to handle our color scheme. Drop this in your CSS file:<br>
</p>

<pre class="brush:php;toolbar:false">:root {
  --background: #ffffff;
  --text-primary: #222222;
  --toggle-bg: #e4e4e7;
  --toggle-hover: #d4d4d8;
}


[data-theme="dark"] {
  --background: #121212;
  --text-primary: #ffffff;
  --toggle-bg: #3f3f46;
  --toggle-hover: #52525b;
}

body {
  background-color: var(--background);
  color: var(--text-primary);
  transition: background-color 0.3s ease, color 0.3s ease;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.theme-toggle {
  border: none;
  padding: 0.5rem;
  border-radius: 9999px;
  background-color: var(--toggle-bg);
  cursor: pointer;
  transition: background-color 0.2s ease;
  align-self: flex-start;
  position: absolute;
  right: 20px;
}

.theme-toggle:hover {
  background-color: var(--toggle-hover);
}

.theme-toggle svg {
    transform-origin: center;
    transition: transform 0.3s ease;
}

.theme-toggle:active svg {
    transform: rotate(30deg);
}

h1 {
  display: flex;
}

.sun-icon {
  display: none;
  width: 24px;
  height: 24px;
}

.moon-icon {
  width: 24px;
  height: 24px;
}

[data-theme="dark"] .sun-icon {
  display: block;
}

[data-theme="dark"] .moon-icon {
  display: none;
}

专业提示:注意到我们如何使用数据主题而不是类?这使得该属性的用途非常清楚,并防止任何潜在的类命名冲突。

对于图标,您可以使用自己的 SVG 或从您最喜欢的图标库中获取一些。我喜欢使用简单的,所以我告诉 Chatgpt 想出这个:

<!-- Replace the empty SVGs with these -->
<svg>



<p>At this point, your toggle should look pretty decent, but it won't actually do anything yet. Don't worry though - in the next section, we'll add the JavaScript that makes it all work!</p>

<p><strong>A quick heads-up:</strong> I've kept the styling minimal on purpose. Feel free to spice it up with your own creative touches. Want a sliding animation? Go for it! Prefer a different icon style? Make it yours!</p>

<p>Ready to make this thing actually work? Let's move on to the JavaScript implementation!</p>

<h2>
  
  
  The JavaScript Implementation (Where It All Comes Together!)
</h2>

<p>Alright, this is where we make our toggle actually, you know... toggle. But don't worry - we're keeping it clean and simple.<br>
</p>

<pre class="brush:php;toolbar:false">const themeToggle = document.querySelector('.theme-toggle');


function toggleTheme() {
  const currentTheme = document.documentElement.getAttribute('data-theme');

  const newTheme = currentTheme === 'dark' ? 'light' : 'dark';

  document.documentElement.setAttribute('data-theme', newTheme);

  localStorage.setItem('theme', newTheme);
}

// Listen for clicks on our toggle
themeToggle.addEventListener('click', toggleTheme);


function initializeTheme() {
  const savedTheme = localStorage.getItem('theme');

  if (savedTheme) {
    document.documentElement.setAttribute('data-theme', savedTheme);
  } else {
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

    document.documentElement.setAttribute(
      'data-theme',
      prefersDark ? 'dark' : 'light'
    );

    localStorage.setItem('theme', prefersDark ? 'dark' : 'light');
  }
}

// Run on page load
initializeTheme();

// Listen for system theme change

window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', (e) => {
    // Only update if user hasn't manually set a preference
    if (!localStorage.getItem('theme')) {
      document.documentElement.setAttribute(
        'data-theme',
        e.matches ? 'dark' : 'light'
      );
    }
  });

让我们来分解一下这里发生的事情,因为实际上发生了一些非常酷的事情:

  1. 当有人单击切换时,我们会检查当前主题并切换到相反的主题
  2. 我们将他们的选择保存在 localStorage 中(因此它在页面加载之间保持不变)
  3. 当页面首次加载时,我们:
    • 检查他们是否保存了偏好设置
    • 如果没有,我们检查他们的系统主题
    • 应用合适的主题
  4. 作为奖励,我们会监听系统主题更改(例如有人在其操作系统上启用深色模式时)

防止错误主题的出现

这是一个常见问题:有时用户在页面加载时会看到错误主题的闪现。超级烦人,对吧?让我们通过在

中添加此脚本来解决这个问题。您的 HTML:
<script>
  // Add this to your <head> before any style sheets
  (function() {
    const savedTheme = localStorage.getItem('theme');
    if (savedTheme) {
      document.documentElement.setAttribute('data-theme', savedTheme);
    } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
      document.documentElement.setAttribute('data-theme', 'dark');
    }
  })();
</script>

它会在加载其他内容之前立即运行,从而防止出现烦人的闪烁。

然后...就是这样!您已经有了一个可以正常工作的黑暗模式开关:

  • 记住用户偏好
  • 尊重系统设置
  • 不会闪现错误的主题
  • 过渡顺利

想让它变得更好吗?让我们继续学习一些有用的技巧,帮助您从优秀走向卓越!

让它变得更好(因为细节很重要!)

让我们从“它有效”切换到“它工作精美”,并进行一些重要但经常被忽视的改进。这些细节将专业实施与快速破解区分开来。

1. 键盘辅助功能

首先,让我们确保每个人都可以使用我们的切换按钮,无论他们如何与设备交互:

// Add this to your existing JavaScript
themeToggle.addEventListener('keydown', (e) => {
    // Toggle on Enter or Space
    if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        toggleTheme();
    }
});

2. 禁用转换

当用户喜欢减少运动时禁用过渡:

@media (prefers-reduced-motion: reduce) {
  body {
    transition: none;
  }
}

3. 处理内容变更

这是许多开发人员错过的东西 - 某些内容可能需要根据主题进行更改。考虑具有不同版本的明/暗模式的图像:

// Add this to your toggleTheme function
function updateThemeSpecificContent(theme) {
    // Find all theme-aware images
    const themeImages = document.querySelectorAll('[data-theme-image]');

    themeImages.forEach(img => {
        const lightSrc = img.getAttribute('data-light-src');
        const darkSrc = img.getAttribute('data-dark-src');

        img.src = theme === 'dark' ? darkSrc : lightSrc;
    });
}

在 HTML 中使用它,如下所示:

<img src="/static/imghwm/default1.png" data-src="/path/to/light-logo.png" class="lazy" data-theme-image data-light- data-dark- alt="在几分钟内构建一个黑暗模式切换(实际上有效)">

4. 防止主题不匹配

有时,保存的主题可能与实际显示的内容不同步。让我们添加一个安全检查:

<button>



<h3>
  
  
  The CSS
</h3>

<p>Here's where things get interesting. We'll use CSS variables (aka custom properties) to handle our color scheme. Drop this in your CSS file:<br>
</p>

<pre class="brush:php;toolbar:false">:root {
  --background: #ffffff;
  --text-primary: #222222;
  --toggle-bg: #e4e4e7;
  --toggle-hover: #d4d4d8;
}


[data-theme="dark"] {
  --background: #121212;
  --text-primary: #ffffff;
  --toggle-bg: #3f3f46;
  --toggle-hover: #52525b;
}

body {
  background-color: var(--background);
  color: var(--text-primary);
  transition: background-color 0.3s ease, color 0.3s ease;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.theme-toggle {
  border: none;
  padding: 0.5rem;
  border-radius: 9999px;
  background-color: var(--toggle-bg);
  cursor: pointer;
  transition: background-color 0.2s ease;
  align-self: flex-start;
  position: absolute;
  right: 20px;
}

.theme-toggle:hover {
  background-color: var(--toggle-hover);
}

.theme-toggle svg {
    transform-origin: center;
    transition: transform 0.3s ease;
}

.theme-toggle:active svg {
    transform: rotate(30deg);
}

h1 {
  display: flex;
}

.sun-icon {
  display: none;
  width: 24px;
  height: 24px;
}

.moon-icon {
  width: 24px;
  height: 24px;
}

[data-theme="dark"] .sun-icon {
  display: block;
}

[data-theme="dark"] .moon-icon {
  display: none;
}

5. 性能优化技巧

这是一个巧妙的技巧,可以防止在不同主题中加载自定义字体时发生布局变化:

<!-- Replace the empty SVGs with these -->
<svg>



<p>At this point, your toggle should look pretty decent, but it won't actually do anything yet. Don't worry though - in the next section, we'll add the JavaScript that makes it all work!</p>

<p><strong>A quick heads-up:</strong> I've kept the styling minimal on purpose. Feel free to spice it up with your own creative touches. Want a sliding animation? Go for it! Prefer a different icon style? Make it yours!</p>

<p>Ready to make this thing actually work? Let's move on to the JavaScript implementation!</p>

<h2>
  
  
  The JavaScript Implementation (Where It All Comes Together!)
</h2>

<p>Alright, this is where we make our toggle actually, you know... toggle. But don't worry - we're keeping it clean and simple.<br>
</p>

<pre class="brush:php;toolbar:false">const themeToggle = document.querySelector('.theme-toggle');


function toggleTheme() {
  const currentTheme = document.documentElement.getAttribute('data-theme');

  const newTheme = currentTheme === 'dark' ? 'light' : 'dark';

  document.documentElement.setAttribute('data-theme', newTheme);

  localStorage.setItem('theme', newTheme);
}

// Listen for clicks on our toggle
themeToggle.addEventListener('click', toggleTheme);


function initializeTheme() {
  const savedTheme = localStorage.getItem('theme');

  if (savedTheme) {
    document.documentElement.setAttribute('data-theme', savedTheme);
  } else {
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

    document.documentElement.setAttribute(
      'data-theme',
      prefersDark ? 'dark' : 'light'
    );

    localStorage.setItem('theme', prefersDark ? 'dark' : 'light');
  }
}

// Run on page load
initializeTheme();

// Listen for system theme change

window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', (e) => {
    // Only update if user hasn't manually set a preference
    if (!localStorage.getItem('theme')) {
      document.documentElement.setAttribute(
        'data-theme',
        e.matches ? 'dark' : 'light'
      );
    }
  });

快速测试清单

发货前,请务必测试以下场景:

  • ✅ 页面刷新保持正确的主题
  • ✅ 尊重系统主题更改(如果没有手动偏好)
  • ✅ 切换功能适用于鼠标和键盘
  • ✅ 加载时不会闪烁错误的主题
  • ✅ 过渡顺利
  • ✅ 适用于所有主要浏览器(是的,甚至是 Safari!)
  • ✅ 主题特定内容正确更新

需要注意的常见问题

  1. 第三方内容:某些嵌入内容可能不尊重您的主题。像这样处理它:
<script>
  // Add this to your <head> before any style sheets
  (function() {
    const savedTheme = localStorage.getItem('theme');
    if (savedTheme) {
      document.documentElement.setAttribute('data-theme', savedTheme);
    } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
      document.documentElement.setAttribute('data-theme', 'dark');
    }
  })();
</script>
  1. 具有透明度的图像:它们在不同的背景下看起来可能是错误的:
// Add this to your existing JavaScript
themeToggle.addEventListener('keydown', (e) => {
    // Toggle on Enter or Space
    if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        toggleTheme();
    }
});

就是这样!您现在拥有一个强大、可访问且用户友好的暗模式实现,可以像冠军一样处理不同的场景。

结论

好了,给你了!我们构建了一个黑暗模式切换器,它不仅可以工作,而且效果非常好。

让我们快速回顾一下我们所取得的成就:

  • 真正记住用户偏好的切换开关?
  • 主题之间的平滑过渡,没有可怕的闪光⚡
  • 系统偏好设置检测是否有效?
  • 从一开始就内置辅助功能♿
  • 性能优化以保持流畅?‍♂️

从这里去哪里?

请随意使用此代码并使其成为您自己的代码。也许添加一些精美的动画,尝试不同的配色方案,或者将其与您现有的设计集成。我们建立的基础足够坚实,可以处理您提出的任何创意。

最后一件事...

深色模式可能看起来只是一个小细节,但正是这些小细节表明您关心用户的体验。另外,这很酷。谁不喜欢好的黑暗模式?

如果您发现这有帮助,请随时与其他开发者分享。如果您提出任何很酷的改进,我很想听听!


让我们保持联系! ?

如果您喜欢本指南并想要更多 Web 开发技巧、技巧以及偶尔关于编程的老爸笑话,请来 X 上和我一起玩!我分享我的开发者之旅中的快速技巧、编码见解和实际解决方案。

?关注我@Peboydcoder

我经常发布关于:

  • Web 开发提示和技巧
  • 前端最佳实践
  • UI/UX 见解
  • 是的,还有更多深色模式欣赏帖子?

过来打个招呼!总是很高兴与关心构建更好网络体验的其他开发人员建立联系。


以上是在几分钟内构建一个黑暗模式切换(实际上有效)的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
@KeyFrames vs CSS过渡:有什么区别?@KeyFrames vs CSS过渡:有什么区别?May 14, 2025 am 12:01 AM

@keyframesandCSSTransitionsdifferincomplexity:@keyframesallowsfordetailedanimationsequences,whileCSSTransitionshandlesimplestatechanges.UseCSSTransitionsforhovereffectslikebuttoncolorchanges,and@keyframesforintricateanimationslikerotatingspinners.

使用页面CMS进行静态站点内容管理使用页面CMS进行静态站点内容管理May 13, 2025 am 09:24 AM

我知道,我知道:有大量的内容管理系统选项可用,而我进行了几个测试,但实际上没有一个是一个,y&#039;知道吗?怪异的定价模型,艰难的自定义,有些甚至最终成为整个&

链接HTML中CSS文件的最终指南链接HTML中CSS文件的最终指南May 13, 2025 am 12:02 AM

链接CSS文件到HTML可以通过在HTML的部分使用元素实现。1)使用标签链接本地CSS文件。2)多个CSS文件可通过添加多个标签实现。3)外部CSS文件使用绝对URL链接,如。4)确保正确使用文件路径和CSS文件加载顺序,优化性能可使用CSS预处理器合并文件。

CSS Flexbox与网格:全面评论CSS Flexbox与网格:全面评论May 12, 2025 am 12:01 AM

选择Flexbox还是Grid取决于布局需求:1)Flexbox适用于一维布局,如导航栏;2)Grid适合二维布局,如杂志式布局。两者在项目中可结合使用,提升布局效果。

如何包括CSS文件:方法和最佳实践如何包括CSS文件:方法和最佳实践May 11, 2025 am 12:02 AM

包含CSS文件的最佳方法是使用标签在HTML的部分引入外部CSS文件。1.使用标签引入外部CSS文件,如。2.对于小型调整,可以使用内联CSS,但应谨慎使用。3.大型项目可使用CSS预处理器如Sass或Less,通过@import导入其他CSS文件。4.为了性能,应合并CSS文件并使用CDN,同时使用工具如CSSNano进行压缩。

Flexbox vs Grid:我应该学习两者吗?Flexbox vs Grid:我应该学习两者吗?May 10, 2025 am 12:01 AM

是的,youshouldlearnbothflexboxandgrid.1)flexboxisidealforone-demensional,flexiblelayoutslikenavigationmenus.2)gridexcelstcelsintwo-dimensional,confffferDesignssignssuchasmagagazineLayouts.3)blosebothenHancesSunHanceSlineHancesLayOutflexibilitibilitibilitibilitibilityAnderibilitibilityAndresponScormentilial anderingStruction

轨道力学(或我如何优化CSS KeyFrames动画)轨道力学(或我如何优化CSS KeyFrames动画)May 09, 2025 am 09:57 AM

重构自己的代码看起来是什么样的?约翰·瑞亚(John Rhea)挑选了他写的一个旧的CSS动画,并介绍了优化它的思维过程。

CSS动画:很难创建它们吗?CSS动画:很难创建它们吗?May 09, 2025 am 12:03 AM

CSSanimationsarenotinherentlyhardbutrequirepracticeandunderstandingofCSSpropertiesandtimingfunctions.1)Startwithsimpleanimationslikescalingabuttononhoverusingkeyframes.2)Useeasingfunctionslikecubic-bezierfornaturaleffects,suchasabounceanimation.3)For

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中