Tombol mode gelap memungkinkan pengguna mengganti skema warna sistem untuk satu situs.
Penggantian diterapkan dengan memperbarui <meta name="color-scheme">: light dark berarti "ikuti preferensi sistem", light atau dark menyematkan skema eksplisit.
Warna (light-dark()), warna sistem, dan UI native semuanya bergantung pada properti color-scheme CSS, sehingga tombol ini berfungsi dengan menjaga properti tersebut tetap sinkron dengan <meta> (lihat Mencerminkan penggantian di CSS).
Tombol persisten, kontrol setelan, atau tidak ada tombol sama sekali?
Sebagian besar situs tidak memerlukan tombol skema warna persisten di UI situs (header, navigasi, footer, dll.). Ikuti preferensi sistem secara default dan, jika penggantian manual diperlukan, tempatkan kontrol di platform setelan terpisah: halaman setelan, panel, atau overlay.
Menyematkan skema pada OS adalah niat yang sah, tetapi jarang terjadi, dan niat yang jarang terjadi termasuk dalam pengungkapan progresif, bukan dalam kontrol yang terlihat setiap saat.
Tombol persisten sebagian besar ditemukan di situs yang ditujukan untuk developer atau yang terkait dengan developer (misalnya, untuk desainer), tempat beralih skema adalah tugas yang jauh lebih sering dilakukan daripada bagi pengguna web biasa. JANGAN tambahkan hanya karena ini adalah pola umum di situs developer: minat developer terhadap kontrol ini tidak mewakili pengguna biasa.
Penerapan
Pertama, ikuti semua langkah di Mode gelap untuk mendukung kedua skema, dengan setelan default ke preferensi sistem.
Model data
Model data untuk tombol mode gelap biasanya mencakup tiga status:
- Sistem (tidak ada nilai tersimpan): UI mengikuti skema warna sistem. Idealnya, ini harus menjadi setelan default.
- Terang (disimpan sebagai
"light"): UI menggunakan tema terang, terlepas dari skema warna sistem. - Gelap (disimpan sebagai
"dark"): UI menggunakan tema gelap, terlepas dari skema warna sistem.
Status ini biasanya disimpan di localStorage dan ditampilkan dalam elemen <meta name="color-scheme"> di head dokumen.
Mencerminkan penggantian di CSS
<meta> hanyalah petunjuk presentasi: setiap deklarasi color-scheme di CSS penulis akan menggantikannya.
Karena Mode gelap menetapkan color-scheme: light dark di :root, memperbarui <meta> saja adalah no-op — CSS menang.
Petakan <meta> kembali ke properti sehingga cascade mengikutinya:
:root {
color-scheme: light dark;
&:has(> head > meta[name="color-scheme"][content="dark"]) {
color-scheme: dark;
}
&:has(> head > meta[name="color-scheme"][content="light"]) {
color-scheme: light;
}
}
JANGAN melakukan hardcode color-scheme: light atau color-scheme: dark sebagai default root; deklarasi dasar HARUS tetap light dark.
CSS TIDAK BOLEH bergantung pada JS: jika JS tidak pernah berjalan, <meta> akan tetap light dark dan situs akan mengikuti preferensi sistem — tidak ada yang rusak.
Persistensi dan pencegahan FOUC
Pertahankan penggantian di localStorage; hapus entri saat kembali ke default sistem.
Untuk menghindari tampilan skema yang salah, terapkan nilai yang disimpan dalam skrip inline (BUKAN type=module, BUKAN defer) yang ditempatkan tepat setelah elemen <meta>:
<meta name="color-scheme" content="light dark">
<script>
document.querySelector('meta[name="color-scheme"]').content = localStorage.getItem("color-scheme") ?? "light dark";
</script>
- Skrip inline ini ada hanya untuk mencegah FOUC. Buat sekecil mungkin; JS tambahan untuk menangani pengalihan skema warna dapat dimuat nanti.
- Dalam kasus yang jarang terjadi, akses
localStoragedapat menampilkan error (misalnya, data situs diblokir), tetapi karena skrip ini tidak melakukan hal lain, satu-satunya efek sampingnya adalah error konsol. Gabungkan dalamtry .. catchjika ini penting. Pastikan tema masih diterapkan ke halaman, meskipun tidak dapat dipertahankan. - Penggantian dapat berubah dari tab lain: tangani peristiwa
storagewindowagar tetap sinkron. - JANGAN gunakan
matchMedia()untuk menghapus nilai yang disimpan saat preferensi sistem berubah agar sesuai. OS banyak pengguna beralih skema secara otomatis berdasarkan waktu; menghapus nilai yang disimpan setiap kali keduanya kebetulan bertepatan akan membuat skema tidak dapat disematkan sama sekali.
Percabangan untuk nilai HTML dan non-warna
Warna tidak memerlukan upaya tambahan: setelah <meta> dipetakan ke color-scheme (di atas), light-dark() akan mengikuti penggantian.
Bagian ini membahas cara menyesuaikan nilai lain (misalnya, font-weight, sumber media, dll.).
Jika halaman hanya mengikuti preferensi sistem, (prefers-color-scheme: dark) dapat digunakan untuk percabangan, termasuk di sumber <picture> atau <video>.
Mengganti skema warna akan menambah kerumitan: preferensi sistem tidak lagi menjadi sumber kebenaran, dan untuk API yang hanya menerima kueri media, tidak ada alternatif langsung.
JANGAN hanya mengandalkan class yang diterapkan JS seperti .dark untuk percabangan, karena class tersebut akan salah jika JS tidak dimuat dan default OS adalah gelap.
Anda dapat menggabungkan kueri media dengan pemilih :root:has(> head > meta[name="color-scheme"][content="dark"]) (atau light) untuk membuat cabang.
Lihat Kombinasi Pemilih & @-rule untuk mengetahui detail tentang cara menerapkan hal ini dengan baik.
Opsi kontrol itu sendiri juga merupakan cabang non-warna: sertakan kedua status dalam markup (ikon plus teks tindakan yang disembunyikan secara visual, misalnya "Beralih ke tema gelap") dan sembunyikan status yang tidak aktif melalui pemilih ini.
display: none juga menghapus opsi redundan dari AT sehingga kontrol tidak memerlukan JS untuk tetap diperbarui saat preferensi sistem berubah.
Untuk media dalam HTML, satu-satunya cara saat ini adalah menyertakan kedua versi sebagai elemen terpisah dan mengaktifkan/menonaktifkan visibilitas dengan tepat.
Menyembunyikan elemen <source> dengan display: none tidak akan berfungsi.
Antarmuka Pengguna
Dua atau tiga negara bagian?
Dalam semua kasus, UI HARUS mendukung pengembalian atau penyetelan skema warna ke sistem.
Sebaiknya tampilkan dua status dalam tombol yang memiliki keterbatasan ruang, seperti tombol persisten di chrome situs (header, navigasi, footer, dll.) yang memiliki ruang terbatas dan penyesuaian setelan biasanya tidak terkait dengan sasaran pengguna.
Kontrol skema warna di platform setelan terpisah (halaman, panel, atau overlay) adalah skenario yang berbeda dan DAPAT mengekspos ketiga status secara eksplisit ("Terang", "Gelap", "Sistem"): di sana, pengguna sudah membuat keputusan yang disengaja tentang perilaku mendatang, dan ada ruang untuk menjelaskan opsi.
Tiga status eksplisit juga diperlukan jika situs menerapkan skema kontekstual (misalnya, mode terang yang lebih redup saat OS dalam mode gelap), karena "Terang" dan "Sistem (saat ini terang)" akan benar-benar berbeda.
Tombol dua status
Saat kontrol tersebut digunakan, kontrol tersebut cenderung menjadi penyesuaian kenyamanan sementara ("saat ini terlalu terang"), bukan memastikan status saat ini dipertahankan dalam jangka panjang. Oleh karena itu, untuk tombol dua status, cukup menampilkan dua dari tiga setelan: sistem (sehingga setelan dapat dikembalikan) dan kebalikan sistem saat ini, yang disimpan sebagai nilai literal saat ini.
Hanya ada dua status:
- Default sistem — tidak ada nilai tersimpan, konten
<meta>light dark. Ditampilkan sebagai nilai yang diselesaikan saat ini (misalnya, ikon matahari saat terang). - Penggantian — disimpan secara persis sama sebagai
lightataudark.
Pada dasarnya, ini adalah kontrol tiga status (light dark, light, dark) yang status eksplisitnya yang cocok dengan preferensi sistem saat ini tidak dapat dijangkau.
Saat pengguna mengaktifkan/menonaktifkan:
- Skema target = kebalikan dari skema yang saat ini dirender (nilai yang disimpan jika ada, atau preferensi sistem). Niat pengguna adalah "memilih kebalikan dari apa yang saya lihat saat ini", BUKAN "memilih kebalikan dari default sistem".
- Jika target berbeda dengan preferensi sistem saat ini, simpan secara literal.
- Jika target cocok dengan preferensi sistem saat ini, pengguna akan mengurungkan penyesuaiannya: hapus nilai yang disimpan. JANGAN simpan — hal itu akan menyematkan skema secara tidak terlihat terhadap perubahan sistem di masa mendatang.
- Tetapkan konten
<meta>ke nilai yang disimpan, ataulight darkjika tidak ada.
PENTING: Perbedaan hanya boleh diperiksa pada waktu penyimpanan, tidak pernah secara retroaktif: nilai tersimpan yang kemudian diubah oleh preferensi sistem agar cocok HARUS dipertahankan. OS banyak pengguna beralih skema secara otomatis berdasarkan waktu; menghapus nilai yang disimpan setiap kali keduanya kebetulan bertepatan akan membuat skema tidak dapat disematkan sama sekali.
Contoh skenario, dimulai dengan OS yang disetel ke mode terang:
- Tombol pengguna. Gelap berbeda dengan preferensi sistem, sehingga
darkdisimpan; situs berubah menjadi gelap. - Setelan OS berubah menjadi gelap. Situs tetap gelap (nilai yang disimpan sekarang cocok dengan preferensi sistem, tetapi tetap dipertahankan).
- Setelan OS berubah kembali menjadi terang. Situs tetap gelap.
- Tombol pengguna. Target (terang) cocok dengan preferensi sistem, sehingga nilai yang disimpan akan dihapus dan situs akan mengikuti sistem lagi.
Tombol tiga status
Jika ada lebih banyak ruang dan pengguna sudah memiliki pola pikir untuk menetapkan preferensi jangka panjang, kontrol tiga status dapat memberikan kejelasan yang lebih baik. Dalam hal ini, model data dipetakan dengan jelas ke tiga opsi UI: sistem, terang, dan gelap.
Untuk mengurangi beban kognitif, opsi "sistem" juga harus menampilkan setelan sistem saat ini, misalnya melalui:
- Ikon, misalnya ikon matahari di kanan bawah ikon sistem
- Teks, misalnya "Sistem (Saat ini terang)"