5️⃣

JavaScript 20 Projects - 5 Light Dark Mode

2023/08/19に公開

前言

這系列是課程 JavaScript Web Projects: 20 Projects to Build Your Portfolio 的筆記,學習利用 Javascript 做出各種互動網站。

以下是這系列的文章:

Number Name
Project 1 Quote Generator
Project 2 Infinity Scroll
Project 3 Picture In Picture
Project 4 Joke Teller
Project 5 Light Dark Mode

目標

實作 Light Dark Mode。

下面是這次要實作的畫面。範例的連結

截圖 2023-08-19 下午9.45.51.png

截圖 2023-08-19 下午9.45.54.png

準備資源

HTML

  1. fontawesome
    • 可以挑選需要的 Icon。
  2. unDraw
    • 挑選圖片,這片可以選兩種顏色來當成 light 跟 dark 模式的圖片。

CSS

  1. Hero Patterns
    • 用來當背景圖案。
  2. How TO - Toggle Switch
    • 用來設定切換模式。

建立 HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Light/Dark Mode</title>
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css"
    />
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <header class="headerBar">
      <!-- Navigation -->
      <nav class="nav">
        <a href="#home">HOME</a>
        <a href="#about">ABOUT</a>
        <a href="#projects">PROJECTS</a>
        <a href="#contact">CONTACT</a>
      </nav>
      <!-- Dark Mode Switch -->
      <div class="theme-switch-wrapper">
        <span id="toggle-icon">
          <span class="toggle-text">Light Mode</span>
          <i class="fas fa-sun"></i>
        </span>
        <label class="theme-switch">
          <input type="checkbox" />
          <div class="slider round"></div>
        </label>
      </div>
    </header>
    <!-- Main Section -->
    <section id="home">
      <div class="title-group">
        <h1>Discover story-worthy<br />travel moments</h1>
        <h2>Best in travel !</h2>
        <img
          src="img/undraw_aircraft_re_light.svg"
          alt="picture"
          class="picture"
          id="picture"
        />
      </div>
    </section>
    <script src="script.js"></script>
  </body>
</html>

建立 CSS

Using CSS custom properties (variables)

這邊介紹一個好用的 CSS 用法,可以用來設定一個網頁的色彩規劃。

可以利用double hyphen (--) 來宣告一個 property,並給他你所要定義的value。

比如這邊在 root 定義主要的背景顏色,那在之後會用到這背景色的地方,就可以利用 var(—property) 的方式直接把在 root 定義好的顏色拿來用了。

:root {
  --main-bg-color: brown;
}

element {
  background-color: var(--main-bg-color);
}

以下是這次設定的顏色提供參考。

:root {
  --primary-color: #43eac1;
  --secondary-color: #1b9999;
  --on-primary: rgb(250, 250, 250);
  --on-background: rgb(66, 66, 66);
  --on-background-alt: rgba(66, 66, 66, 0.7);
  --background: rgb(255, 255, 255);
  --box-shadow: 0 5px 20px 1px rgba(0, 0, 0, 0.5);
}

[data-theme="dark"] {
  --primary-color: #6c63ff;
  --secondary-color: #03dac5;
  --on-primary: #000;
  --on-background: rgba(255, 255, 255, 0.9);
  --on-background-alt: rgba(255, 255, 255, 0.7);
  --background: #121212;
}

思考 javascript 所需要的動作

  1. 如何切換兩個模式?
  2. 怎麼設定切換顏色?

動作解讀

如何切換兩個模式?

  1. 先利用 DOM 來控制 toggle 元素。
  2. 設定 function switchTheme() ,確認 toggle checked 的狀態來設定 lightMode() / darkMode()
  3. 設定 Event Listener 。
const toggleSwitch = document.querySelector('input[type="checkbox"]');

// Switch Theme Dynamically
function switchTheme(event) {
  if (event.target.checked) {
    document.documentElement.setAttribute("data-theme", "dark");
    darkMode();
  } else {
    document.documentElement.setAttribute("data-theme", "light");
    lightMode();
  }
}

// Event Listener
toggleSwitch.addEventListener("change", switchTheme);

怎麼設定切換顏色?

  1. 利用 DOM 來控制 Icon 跟 image 元素。
  2. 這裡示範在 lightMode() / darkMode() 分別設定要替換的圖片、文字與 class (用來替換Icon)。
const toggleIcon = document.getElementById("toggle-icon");
const image = document.getElementById("picture");

// Dark Mode Styles
function darkMode() {
  image.src = `img/undraw_aircraft_re_dark.svg`;
  toggleIcon.children[0].textContent = "Dark Mode";
  toggleIcon.children[1].classList.replace("fa-sun", "fa-moon");
}

// Light Mode Styles
function lightMode() {
  image.src = `img/undraw_aircraft_re_light.svg`;
  toggleIcon.children[0].textContent = "Light Mode";
  toggleIcon.children[1].classList.replace("fa-moon", "fa-sun");
}

// Event Listener
toggleSwitch.addEventListener("change", switchTheme);

用 LocalStorage 來存使用者資料

可以 LocalStorage 來儲存資料,當你關掉瀏覽器再次開啟時,他會以上次關掉時所記住的模式來開啟。詳細可以看Window: localStorage property

  1. 要先新增在 LocalStorage 的Key,所以在 switchTheme() 分別設定theme ,並可以在 Develop Tool 的Application 中看到新增的 Key 以及 value 。
    • localStorage.setItem("theme", "dark");
    • localStorage.setItem("theme", “light”);

Image.png

  1. 接下來就是要設定當瀏覽器重新開啟時,要確認當前的模式是什麼?若有值的話,接著就設定模式相關的 value 。
// Switch Theme Dynamically
function switchTheme(event) {
  if (event.target.checked) {
    document.documentElement.setAttribute("data-theme", "dark");
    localStorage.setItem("theme", "dark");
    darkMode();
  } else {
    document.documentElement.setAttribute("data-theme", "light");
    localStorage.setItem("theme", "light");
    lightMode();
  }
}

// Event Listener
toggleSwitch.addEventListener("change", switchTheme);

// Check Local Storage For Theme
const currentTheme = localStorage.getItem("theme");
if (currentTheme) {
  document.documentElement.setAttribute("data-theme", currentTheme);
  if (currentTheme === "dark") {
    toggleSwitch.checked = true;
    darkMode();
  }
}

完整的Javascript程式碼

const toggleSwitch = document.querySelector('input[type="checkbox"]');
const toggleIcon = document.getElementById("toggle-icon");
const image = document.getElementById("picture");

// Dark Mode Styles
function darkMode() {
  image.src = `img/undraw_aircraft_re_dark.svg`;
  toggleIcon.children[0].textContent = "Dark Mode";
  toggleIcon.children[1].classList.replace("fa-sun", "fa-moon");
}

// Light Mode Styles
function lightMode() {
  image.src = `img/undraw_aircraft_re_light.svg`;
  toggleIcon.children[0].textContent = "Light Mode";
  toggleIcon.children[1].classList.replace("fa-moon", "fa-sun");
}

// Switch Theme Dynamically
function switchTheme(event) {
  if (event.target.checked) {
    document.documentElement.setAttribute("data-theme", "dark");
    localStorage.setItem("theme", "dark");
    darkMode();
  } else {
    document.documentElement.setAttribute("data-theme", "light");
    localStorage.setItem("theme", "light");
    lightMode();
  }
}

// Event Listener
toggleSwitch.addEventListener("change", switchTheme);

// Check Local Storage For Theme
const currentTheme = localStorage.getItem("theme");

if (currentTheme) {
  document.documentElement.setAttribute("data-theme", currentTheme);

  if (currentTheme === "dark") {
    toggleSwitch.checked = true;
    darkMode();
  }
}

文章參考

The Ultimate Guide on Designing a Dark Theme for your Android app.

Discussion