搜尋
首頁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

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具