Dark mode bukan sekadar membalik hitam dan putih: latar perlu diturunkan ke tingkat yang tepat, teks tidak boleh menjadi putih penuh yang menyilaukan, dan aksen perlu versi yang tetap kontras di atas latar gelap. Upaya itu terasa mahal bila setiap komponen menulis ulang warnanya sendiri — dan terasa ringan bila seluruh halaman membaca token semantik. Strateginya tiga lapis: token semantik sebagai perantara, media query prefers-color-scheme
sebagai penimpa otomatis, dan fungsi light-dark()
— Baseline 2024 — untuk nilai ganda pada satu deklarasi. Dasar penimpaan token per tema sudah kita lihat pada Chapter Custom Properties dan Theming
; di sini kita menghubungkannya dengan preferensi pengguna.
Token Semantik Plus Media Query #
Langkah pertama adalah memastikan komponen tidak pernah membaca warna mentah, melainkan token semantik seperti --teks dan --latar-kartu. Dengan begitu, dark mode cukup mendefinisikan ulang token di :root di dalam media query:
:root {
color-scheme: light dark;
--latar-halaman: rgb(248, 250, 252);
--latar-kartu: rgb(255, 255, 255);
--teks: rgb(15, 23, 42);
--teks-samping: rgb(71, 85, 105);
--garis: rgb(226, 232, 240);
--aksen: rgb(29, 78, 216);
}
@media (prefers-color-scheme: dark) {
:root {
--latar-halaman: rgb(2, 6, 23);
--latar-kartu: rgb(15, 23, 42);
--teks: rgb(226, 232, 240);
--teks-samping: rgb(148, 163, 184);
--garis: rgb(30, 41, 59);
--aksen: rgb(147, 197, 253);
}
}
.kartu {
background-color: var(--latar-kartu);
color: var(--teks);
border: 1px solid var(--garis);
border-radius: 12px;
padding: 16px;
}Mari kita telaah keputusannya:
color-scheme: light darkpada:root: deklarasi color-scheme menginformasikan bahwa halaman mendukung kedua mode. Browser menyesuaikan widget bawaan — scrollbar, checkbox, dan input — serta mengaktifkan fungsilight-dark()pada seluruh pohon dokumen.- Media query menimpa token, bukan komponen: blok gelap hanya menulis ulang enam variabel. Tidak ada satu pun aturan
.kartuyang disentuh, karena semua komponen membaca token lewatvar(). - Pemilihan nilai gelap yang sengaja: latar tidak hitam murni melainkan
rgb(2, 6, 23)danrgb(15, 23, 42); teks tidak putih penuh melainkanrgb(226, 232, 240); aksen justru mengambil tingkatan terang dari ramp (150-an) agar tetap kontras di atas latar gelap.
Fungsi light-dark() untuk Nilai Ganda #
Untuk warna yang berubah pada satu elemen saja, fungsi light-dark() menuliskan kedua nilai dalam satu deklarasi: nilai pertama dipakai di mode terang, nilai kedua di mode gelap:
.status {
color: light-dark(rgb(22, 163, 74), rgb(74, 222, 128));
}Deklarasi ini menggantikan sepasang blok :root dan media query untuk kasus sederhana, dan tetap dapat menerima token: light-dark(var(--hijau-700), var(--hijau-400)). Syaratnya sama seperti token: elemen harus berada di bawah color-scheme: light dark, jika tidak browser menganggap halaman hanya mendukung mode terang. Fungsi ini cocok untuk warna yang jarang berulang; untuk palet utama, pola token semantik tetap lebih mudah dipelihara karena satu penimpa menggerakkan semua komponen. Apa pun jalurnya, pasangan terang-gelap perlu diperiksa kontrasnya keduanya — teknik pengukurannya kita praktikkan pada Chapter Color Contrast
.
Demo: Satu Palet, Dua Mode #
Demo chapter ini menampilkan kartu berisi status hijau dari light-dark(). Pada mode terang hasilnya sebagai berikut; pada mode gelap seluruh nilai berganti sesuai media query tanpa perubahan kode.
Hasil di Browser:
Kartu tampil berlatar rgb(255, 255, 255) dengan teks rgb(15, 23, 42)
dan aksen rgb(29, 78, 216) — nilai terang dari token semantik.
Status "Aktif" tampil hijau rgb(22, 163, 74), nilai pertama dari
light-dark(); di mode gelap fungsinya akan menghasilkan rgb(74, 222, 128).Keempat nilai terang tersebut diverifikasi otomatis melalui penanda data-expected. Uji sisi gelap dengan mengemulasi preferensi di DevTools, atau lanjutkan ke Chapter Prefers-color-scheme
untuk membahas media query-nya lebih teknis, dan ke Chapter Theme Switching Overview
untuk memberi pengguna sakelar manual yang menimpa preferensi sistem.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
contoh-token-gelap.css
Unduh berkas:root {
color-scheme: light dark;
--latar-halaman: rgb(248, 250, 252);
--latar-kartu: rgb(255, 255, 255);
--teks: rgb(15, 23, 42);
--teks-samping: rgb(71, 85, 105);
--garis: rgb(226, 232, 240);
--aksen: rgb(29, 78, 216);
}
@media (prefers-color-scheme: dark) {
:root {
--latar-halaman: rgb(2, 6, 23);
--latar-kartu: rgb(15, 23, 42);
--teks: rgb(226, 232, 240);
--teks-samping: rgb(148, 163, 184);
--garis: rgb(30, 41, 59);
--aksen: rgb(147, 197, 253);
}
}
body {
background-color: var(--latar-halaman);
color: var(--teks);
}
.kartu {
background-color: var(--latar-kartu);
color: var(--teks);
border: 1px solid var(--garis);
border-radius: 12px;
padding: 16px;
}
.aksen { color: var(--aksen); }
.status {
color: light-dark(rgb(22, 163, 74), rgb(74, 222, 128));
}