是否曾經花費數小時實現黑暗模式切換,卻在頁面刷新時閃爍著令人眼花繚亂的白色?或者更糟的是,它是否完全忽略了使用者的系統偏好?是的,我也是。 ?
事情是這樣的 - 黑暗模式不再只是一個流行的功能。隨著越來越多的人在夜間編碼(被指控有罪)和可訪問性變得越來越重要,實施良好的黑暗模式實際上是現代網站或網路應用程式的必備條件。但要做好它可能會非常棘手。
好消息?在摸索各種實現並與 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中文網其他相關文章!