Langkau ke kandungan
WANCODE
EN

Suis Mod Gelap

Ikut skema warna sistem secara lalai, benarkan pengguna menukarnya, ingat pilihan mereka, dan elakkan kilatan putih semasa halaman dimuatkan.

Pratonton langsung Buka dalam Playground
theme.css
:root {
  color-scheme: light;
  --bg: #ffffff;
  --text: #1c1c1e;
  --muted: #5b5b66;
  --surface: #f2f2f5;
}

:root[data-theme="dark"] {
  color-scheme: dark;   /* dark scrollbars and form controls too */
  --bg: #121214;
  --text: #ececf1;
  --muted: #a1a1aa;
  --surface: #1f1f23;
}

body {
  background: var(--bg);
  color: var(--text);
}
theme-init.js
// Put this in <head>, BEFORE your stylesheet, so the right theme
// is applied before the first paint (no white flash).
(function () {
  let saved = null;
  try {
    saved = localStorage.getItem("theme");
  } catch {
    // storage blocked — just follow the system
  }
  const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
  document.documentElement.dataset.theme = saved || (prefersDark ? "dark" : "light");
})();
theme-toggle.js
const STORAGE_KEY = "theme";
const media = window.matchMedia("(prefers-color-scheme: dark)");
const toggle = document.getElementById("theme-toggle");

function savedTheme() {
  try {
    return localStorage.getItem(STORAGE_KEY);
  } catch {
    return null;
  }
}

function applyTheme(theme) {
  document.documentElement.dataset.theme = theme;
  toggle.setAttribute("aria-pressed", String(theme === "dark"));
}

toggle.addEventListener("click", () => {
  const next = document.documentElement.dataset.theme === "dark" ? "light" : "dark";
  try {
    localStorage.setItem(STORAGE_KEY, next);
  } catch {
    // can't save — the toggle still works for this visit
  }
  applyTheme(next);
});

// Follow system changes only while the user hasn't chosen
media.addEventListener("change", (event) => {
  if (!savedTheme()) applyTheme(event.matches ? "dark" : "light");
});

applyTheme(savedTheme() || (media.matches ? "dark" : "light"));

Mod gelap yang baik ada tiga lapisan: pemboleh ubah CSS simpan warna, atribut data-theme pada <html> memilih satu set, dan sedikit JavaScript menentukan yang mana — pilihan yang disimpan jika ada, jika tiada ikut pilihan sistem operasi.

Baris demi baris

  • Komponen hanya guna var(--bg), var(--text)… Menukar tema mengubah pemboleh ubah di satu tempat sahaja; bahagian lain tak perlu tahu.
  • color-scheme: dark beritahu pelayar supaya lukis bahagiannya sendiri (scrollbar, input, pemilih tarikh) dalam warna gelap juga.
  • Skrip init kecil ini berjalan dalam <head> sebelum apa-apa dilukis, jadi pengguna mod gelap tak nampak halaman putih dahulu. Sebab itu ia diasingkan daripada skrip suis, yang perlukan butang sudah wujud.
  • aria-pressed jadikan butang biasa sebagai butang togol untuk pembaca skrin ("Dark mode, toggle button, pressed").
  • Setiap panggilan localStorage dibalut dengan try/catch: storan boleh dimatikan atau penuh, dan suis masih patut berfungsi untuk lawatan semasa.
  • Listener change pada matchMedia terus mengikut sistem (contohnya mod gelap automatik waktu malam) — tetapi hanya sehingga pengguna membuat pilihan.

Semak kontras dalam kedua-dua tema. Mod gelap bukan sekadar warna terbalik — hitam pekat dengan teks putih pekat terlalu tajam; kelabu yang sedikit cerah lebih selesa untuk mata.

Cara guna

HTML
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="theme-init.js"></script>
    <link rel="stylesheet" href="theme.css">
  </head>
  <body>
    <button type="button" id="theme-toggle" aria-pressed="false">Dark mode</button>
    <script src="theme-toggle.js"></script>
  </body>
</html>