Cara Membuat Dark Mode Dengan Css

dark mode adalah fitur kecil yang sering membuat perbedaan besar bagi kenyamanan pengguna, dan saya sendiri lebih sering memakainya daripada mode terang. pola di artikel ini, CSS variables plus localStorage, adalah yang selalu saya pakai di project, dan bagian terpentingnya: preferensi tema harus tersimpan supaya pengguna tidak perlu memilih ulang setiap kunjungan.
kita akan bahas dari cara paling sederhana sampai pola yang siap produksi: mencegah flash halaman terang saat load, mengikuti tema sistem operasi, dan versi Tailwind CSS untuk kalian yang sudah memakainya.
Fondasi: CSS Variables untuk Tema
intinya dark mode adalah mengganti palet warna seluruh halaman, dan cara paling rapi melakukannya di CSS modern adalah lewat CSS variables, dikenal juga sebagai custom properties. kita definisikan semua warna sebagai variabel, lalu tema gelap cukup menimpa nilai variabelnya saja:
:root {
--bg: #ffffff;
--text: #333333;
--card: #f4f4f4;
--primary: #4CAF50;
}
[data-theme="dark"] {
--bg: #1a1a1a;
--text: #ffffff;
--card: #2d2d2d;
--primary: #66BB6A;
}
body { background: var(--bg); color: var(--text); }
.card { background: var(--card); }
.btn { background: var(--primary); }
yang terjadi di balik layar:
:rootadalah selector untuk elemen<html>, tempat default semua variabel didefinisikan[data-theme="dark"]menargetkan elemen yang punya attributedata-theme="dark", yang akan kita pasang ke<html>- semua elemen memakai
var(--nama-variabel)alih-alih warna langsung, jadi satu perubahan nilai di atas mengubah seluruh halaman
aturan emasnya: jangan pernah menulis warna langsung di komponen, selalu lewat variabel. kalau ada satu komponen yang masih memakai background: #ffffff mentah, komponen itu tidak akan ikut berubah saat dark mode aktif, dan bug seperti itu paling menjengkelkan untuk dicari.
Toggle dengan JavaScript
setelah CSS siap, kita butuh tombol untuk berpindah tema:
<button id="themeToggle">๐ Dark Mode</button>
lalu JavaScript-nya:
const toggle = document.getElementById('themeToggle');
// cek preferensi tersimpan
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);
toggle.addEventListener('click', () => {
const current = document.documentElement.getAttribute('data-theme');
const newTheme = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
});
mari bedah alurnya:
localStorage.getItem('theme')membaca preferensi tersimpan, kalau belum ada pakailightsebagai bawaandocument.documentElementadalah elemen<html>, attributedata-themedipasang di sana supaya selector CSS[data-theme="dark"]bekerja- saat tombol diklik, tema saat ini dibaca, dibalik, lalu dipasang kembali ke
<html> - pilihan baru disimpan ke
localStoragesupaya kunjungan berikutnya langsung memakai tema yang sama
soal cara kerja localStorage secara mendalam, saya bahas tuntas di cara menggunakan localstorage di javascript.
Percantik tombolnya
tombol yang cuma bertuliskan emoji statis terasa kurang hidup. kita bisa ganti teks dan ikonnya mengikuti tema:
function updateButton(theme) {
toggle.textContent = theme === 'dark' ? 'โ๏ธ Light Mode' : '๐ Dark Mode';
}
// panggil saat pertama load
updateButton(savedTheme);
// panggil ulang setiap toggle
toggle.addEventListener('click', () => {
// ... logika toggle seperti di atas
updateButton(newTheme);
});
dengan ini tombol selalu menampilkan aksi yang akan terjadi, bukan keadaan saat ini, pengalaman yang jauh lebih jelas untuk user.
Deteksi Preferensi Sistem Operasi
banyak pengguna sudah mengatur tema gelap di sistem operasi atau browser mereka, dan website yang langsung mengikuti pengaturan itu terasa canggih. caranya lewat prefers-color-scheme:
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
// hanya pakai preferensi sistem kalau user belum pernah memilih manual
if (prefersDark.matches && !localStorage.getItem('theme')) {
document.documentElement.setAttribute('data-theme', 'dark');
}
// ikuti perubahan real-time, misal sistem ganti tema otomatis saat malam
prefersDark.addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
document.documentElement.setAttribute(
'data-theme',
e.matches ? 'dark' : 'light'
);
}
});
perhatikan syarat !localStorage.getItem('theme') di kedua blok: preferensi sistem hanya dipakai selama user belum pernah memilih manual. begitu user menekan tombol toggle, pilihan mereka yang menang, tidak lagi ditimpa perubahan sistem. inilah perilaku yang diharapkan dari aplikasi modern.
Cara murni CSS tanpa JavaScript
kalau kebutuhan kalian cuma mengikuti tema sistem tanpa tombol manual, ada jalan yang lebih pendek, semuanya cukup di CSS:
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #ffffff;
--card: #2d2d2d;
--primary: #66BB6A;
}
}
tidak ada JavaScript, tidak ada tombol, halaman otomatis gelap di pengguna yang sistemnya gelap. kekurangannya jelas: user tidak bisa memilih manual kalau seleranya beda dari sistem. untuk itu, pola kombinasi yang sudah kita bahas adalah yang paling lengkap.
Mencegah Flash Terang saat Halaman Dimuat
sampai di sini ada satu bug yang mungkin sudah kalian perhatikan: script tema ada di akhir halaman atau di file JavaScript terpisah, sementara halaman dirender lebih dulu. akibatnya pengguna dark mode melihat halaman flash putih sekejap sebelum jadi gelap. istilahnya flash of unstyled theme, dan cara mencegahnya sederhana: jalankan cek tema sebelum halaman digambar, tepatnya script kecil inline di dalam <head>:
<head>
<script>
// jalankan sebelum CSS dirender untuk mencegah flash
const theme = localStorage.getItem('theme');
if (theme === 'dark' ||
(!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.setAttribute('data-theme', 'dark');
}
</script>
<!-- CSS dan script lainnya -->
</head>
script ini kecil, sinkron, dan jalan sebelum browser menggambar apa pun, jadi attribute data-theme sudah terpasang saat CSS pertama kali dievaluasi. script utama yang mengurus tombol tetap di file JavaScript biasa, tidak masalah kalau itu jalan belakangan.
Transisi Halus antar Tema
perpindahan warna yang tiba-tiba terasa kasar di mata, tambahkan transisi supaya perpindahannya mulus:
body, .card, .btn {
transition: background-color 0.3s ease, color 0.3s ease;
}
atau sekalian global untuk semua elemen:
* {
transition: background-color 0.2s ease, color 0.2s ease;
}
hati-hati dengan selector *, di halaman dengan banyak elemen ini bisa sedikit memberatkan performa. untuk kebanyakan website kecil sampai menengah, efeknya tidak terasa, tapi kalau halaman kalian sudah kompleks, batasi transisi ke elemen yang memang berubah warna saja.
Dark Mode dengan Tailwind CSS
buat kalian yang memakai Tailwind, polanya serupa tapi memakai class dark alih-alih attribute data-theme. pertama, set mode di tailwind.config.js:
module.exports = {
darkMode: 'class',
// ...
}
lalu di markup, tulis class versi gelap dengan prefix dark::
<body class="bg-white text-gray-900 dark:bg-gray-900 dark:text-white">
<div class="bg-gray-100 dark:bg-gray-800 p-4 rounded">
<h1>Judul Artikel</h1>
</div>
</body>
JavaScript toggle-nya tinggal menambah atau menghapus class dark pada <html>:
document.documentElement.classList.toggle('dark');
// simpan preferensi
const isDark = document.documentElement.classList.contains('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
kalau ingin mengikuti sistem operasi, Tailwind menyediakan mode media sebagai alternatif, tapi mode class lebih fleksibel karena mendukung toggle manual sekaligus deteksi sistem lewat sedikit kode tambahan.
Polesan: color-scheme dan Meta Theme
dua detail kecil yang sering terlewat tapi menaikkan kualitas hasil:
pertama, properti color-scheme memberitahu browser tema bawaan elemen, supaya scrollbar, form input, dan kontrol native ikut gelap:
:root { color-scheme: light; }
[data-theme="dark"] { color-scheme: dark; }
kedua, meta tag theme-color mengubah warna address bar di browser mobile mengikuti tema:
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#1a1a1a" media="(prefers-color-scheme: dark)">
dua tambahan ini membuat dark mode kalian terasa native, bukan sekadar ganti warna latar.
Checklist Sebelum Rilis
sebelum fitur dark mode kalian naik production, cek daftar ini:
- semua warna lewat CSS variables, tidak ada warna mentah yang tertinggal
- flash terang sudah dicegah dengan script di
<head> - preferensi tersimpan di localStorage dan dihormati di kunjungan berikutnya
- deteksi sistem jalan hanya saat belum ada preferensi manual
- kontras teks tetap terbaca di kedua tema, cek dengan devtools atau tool kontras online
- gambar dan logo tetap terlihat di latar gelap, tambah background kalau perlu
- transisi halus dan tidak mengganggu
Kesimpulan
dark mode yang baik dibangun di atas CSS variables: semua warna didefinisikan sebagai variabel, tema gelap menimpa nilainya lewat attribute data-theme, dan JavaScript toggle hanya bertugas mengganti attribute serta menyimpan pilihan ke localStorage. deteksi prefers-color-scheme melengkapi dengan mengikuti sistem operasi, dan script kecil di <head> mencegah flash terang saat load.
pola ini sama di semua framework, baik vanilla HTML, React, Vue, maupun Tailwind, yang berubah cuma cara menulis markupnya. sekali kalian menerapkan pola lengkap ini di satu project, menerapkannya di project berikutnya tinggal salin tempel.
Baca Juga Mengenai :
Pertanyaan yang Sering Diajukan
Bagaimana cara membuat dark mode paling sederhana?
Pakai CSS variables dan attribute data-theme. Definisikan warna terang di :root, lalu override warnanya di selector [data-theme="dark"]. Toggle tinggal mengganti attribute di elemen html lewat JavaScript, seluruh warna ikut berubah otomatis.
Kenapa halaman flash terang dulu sebelum jadi gelap?
Itu disebut flash of unstyled theme, terjadi karena script theme dijalankan setelah halaman dirender. Solusinya taruh script kecil di dalam head sebelum CSS dimuat, supaya attribute data-theme terpasang sebelum browser menggambar halaman.
Bagaimana cara mengikuti tema sistem operasi user?
Gunakan media query prefers-color-scheme. Kalau cuma mau mengikuti sistem, cukup tulis @media (prefers-color-scheme: dark) berisi override variabel warna, tanpa JavaScript sama sekali. Kalau mau user bisa memilih manual, gabungkan dengan data-theme dan cek matchMedia.
Apakah localStorage aman untuk menyimpan preferensi tema?
Aman, karena tema bukan data sensitif. localStorage menyimpan string sederhana seperti "dark" atau "light" di browser user, jadi preferensi bertahan walau browser ditutup. Yang tidak boleh disimpan di localStorage adalah data sensitif seperti token dan password.
Bagaimana dark mode dengan Tailwind CSS?
Tailwind memakai class dark pada elemen html. Tambahkan darkMode: "class" di tailwind.config.js, lalu tulis class seperti dark:bg-gray-900 dark:text-white di elemen. Toggle-nya sama, ganti class dark pada html dengan JavaScript.
Apakah dark mode berpengaruh ke SEO?
Dark mode tidak berpengaruh langsung ke ranking, tapi berpengaruh ke pengalaman user dan aksesibilitas yang merupakan sinyal tidak langsung. Yang penting secara teknis: jangan pakai teknik yang menyembunyikan konten, dan pastikan kontras warna tetap terbaca di kedua tema.

