是否曾经花费数小时实现黑暗模式切换,却在页面刷新时闪烁着令人眼花缭乱的白色?或者更糟糕的是,它是否完全忽略了用户的系统偏好?是的,我也是。 ?
事情是这样的 - 黑暗模式不再只是一个流行的功能。随着越来越多的人在夜间编码(被指控有罪)和可访问性变得越来越重要,实施良好的黑暗模式实际上是现代网站或网络应用程序的必备条件。但要做好它可能会非常棘手。
好消息?在摸索各种实现并与 localStorage 进行斗争之后,我终于破解了黑暗模式切换的代码:
在这篇文章中,我将引导您构建一个您真正想要使用的黑暗模式切换开关。没有过于复杂的解决方案,没有不必要的依赖项 - 只有干净、可以立即实现的工作代码。
让我们先把无聊的部分抛开 - 但我保证保持简短!
您可能已经拥有所需的一切,但只是为了确保我们达成共识:
在我们开始之前,先快速浏览一下我们最终会得到什么。没有花哨的 UI 库或复杂的设置 - 只是一个简单、流畅的切换,如下所示:
不要担心让它看起来像这样 - 重要的是它会完美地工作。我们将首先关注功能,然后您可以根据需要设计它的样式。
最好的部分?我们要构建的所有内容都适用于:
准备好动手了吗?让我们从基础开始吧!
好吧,让我们动手吧!首先,我们将建立基本结构。
我们将从一些极其简单的 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' ); } });
让我们来分解一下这里发生的事情,因为实际上发生了一些非常酷的事情:
这是一个常见问题:有时用户在页面加载时会看到错误主题的闪现。超级烦人,对吧?让我们通过在
中添加此脚本来解决这个问题。您的 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>
它会在加载其他内容之前立即运行,从而防止出现烦人的闪烁。
然后...就是这样!您已经有了一个可以正常工作的黑暗模式开关:
想让它变得更好吗?让我们继续学习一些有用的技巧,帮助您从优秀走向卓越!
让我们从“它有效”切换到“它工作精美”,并进行一些重要但经常被忽视的改进。这些细节将专业实施与快速破解区分开来。
首先,让我们确保每个人都可以使用我们的切换按钮,无论他们如何与设备交互:
// Add this to your existing JavaScript themeToggle.addEventListener('keydown', (e) => { // Toggle on Enter or Space if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggleTheme(); } });
当用户喜欢减少运动时禁用过渡:
@media (prefers-reduced-motion: reduce) { body { transition: none; } }
这是许多开发人员错过的东西 - 某些内容可能需要根据主题进行更改。考虑具有不同版本的明/暗模式的图像:
// 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 data-theme-image data-light-src="/path/to/light-logo.png" data-dark-src="/path/to/dark-logo.png" alt="在几分钟内构建一个黑暗模式切换(实际上有效)">
有时,保存的主题可能与实际显示的内容不同步。让我们添加一个安全检查:
<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; }
这是一个巧妙的技巧,可以防止在不同主题中加载自定义字体时发生布局变化:
<!-- 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' ); } });
发货前,请务必测试以下场景:
<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>
// 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
我经常发布关于:
过来打个招呼!总是很高兴与关心构建更好网络体验的其他开发人员建立联系。
以上是在几分钟内构建一个黑暗模式切换(实际上有效)的详细内容。更多信息请关注PHP中文网其他相关文章!