ホームページ > ウェブフロントエンド > CSSチュートリアル > ダークモードトグルを数秒で構築 (実際に機能します)

ダークモードトグルを数秒で構築 (実際に機能します)

Susan Sarandon
リリース: 2024-11-10 03:01:02
オリジナル
422 人が閲覧しました

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

ダーク モードの切り替えを実装するのに何時間も費やした結果、ページの更新時に目がくらむほど白く点滅したことはありませんか?それともさらに悪いことに、ユーザーのシステム設定を完全に無視しているのでしょうか?はい、私もです。 ?

ここで重要なのは、ダークモードはもはや単なる流行の機能ではないということです。夜間にコーディングする人が増え(有罪となります)、アクセシビリティの重要性がますます高まっているため、適切に実装されたダーク モードは、最新の Web サイトや Web アプリには実質的に必須となっています。しかし、正しく理解するのは驚くほど難しい場合があります。

良い知らせですか?さまざまな実装を手探りし、localStorage と格闘した結果、最終的に次のようなダーク モード切り替えのコードを解読しました。

  • ユーザーの設定を実際に記憶します
  • リロード時に間違ったテーマをフラッシュしません
  • システム環境設定とうまく連携します
  • 実装には文字通り 5 分かかります

この投稿では、実際に使用するダーク モード トグルの構築について説明します。過度に複雑なソリューションや不要な依存関係はなく、すぐに実装できるクリーンで動作するコードだけです。

前提条件 (必要なもの)

最初に退屈な部分を片付けましょう - ただし、短くすることを約束します!

必要なものはすでにすべて揃っていると思いますが、同じ認識を持っていることを確認してください:

  • 基本的な HTML ( が何であるかはご存知でしょう)
  • ある程度の CSS 知識 (特に CSS 変数 - ただし、説明しながら進めていきます)
  • バニラ 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. おまけに、システム テーマの変更 (誰かが OS でダーク モードを有効にしたときなど) をリッスンします

間違ったテーマのフラッシュを防ぐ

これは一般的な問題です。ページが読み込まれるときに、ユーザーに間違ったテーマのフラッシュが表示されることがあります。とても迷惑ですよね?このスクリプトを

に追加してこの問題を修正しましょう。 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 data-theme-image data-light-src="/path/to/light-logo.png" data-dark-src="/path/to/dark-logo.png" 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 に関する洞察
  • そして、ダーク モードの感謝の投稿も増えます?

お立ち寄りください!より良い Web エクスペリエンスの構築に関心を持つ開発者仲間とつながるのをいつも楽しみにしています。


以上がダークモードトグルを数秒で構築 (実際に機能します)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート