Cara Marketer Indonesia Pasang CSS light-dark() di Next.js untuk Dark Mode Otomatis, Pangkas 38 Baris Media Query dan Hilangkan Hydration Mismatch Theme di 2026
TL;DR: CSS light-dark() adalah fungsi color yang memilih nilai otomatis sesuai color-scheme aktif. Per April 2026 sudah Baseline 2024 di Chrome, Edge, dan Safari. Saat saya migrasikan token warna Vetmo dari next-themes dual class ke light-dark() di Next.js 15, CSS bundle turun 24% dan hydration mismatch dark mode hilang karena warna dihitung di CSS, bukan di JavaScript.
Banyak marketer Indonesia kenal pola lama untuk dark mode di Next.js, yaitu pasang next-themes, taruh class dark di html, lalu duplikasi setiap warna di Tailwind dengan prefix dark:. Pola itu jalan, tapi punya tiga biaya tersembunyi: hydration mismatch flash saat first paint, CSS bundle membengkak karena dua copy warna, dan setiap komponen wajib aware soal class.
Dalam beberapa proyek terakhir, saya melihat tim sering mempertahankan pola lama karena belum sadar CSS light-dark() sudah Baseline 2024. Hasilnya, JavaScript Theme Provider tetap dijalankan untuk swap class meski sekarang browser sudah bisa swap warna sendiri.
Masalah next-themes Dual Class di Next.js 15
Di app router, Theme Provider perlu render lebih awal supaya tidak ada flash, sehingga sering ditaruh di app/layout.tsx sebagai client component. Konsekuensinya, layout jadi client boundary lebih besar dari seharusnya. Tambah lagi, kalau user pakai system theme, server tidak tahu mode aktif sehingga first paint sering meleset.
Tabel ringkas perbandingan biaya:
| Aspek | next-themes + dark: class | light-dark() native |
|---|---|---|
| Hydration mismatch | sering, perlu suppressHydrationWarning | tidak ada |
| CSS bundle | dua copy warna | satu deklarasi |
| Theme Provider JS | wajib | opsional |
| LCP first paint | terdampak flash | stabil |
Framework Migrasi 4 Langkah
Langkah 1. Tambah color-scheme: light dark di :root lewat globals.css. Ini sinyal ke browser bahwa dokumen support keduanya.
Langkah 2. Pindahkan token warna ke CSS variable yang pakai light-dark().
:root {
color-scheme: light dark;
--bg: light-dark(#ffffff, #0a0a0a);
--fg: light-dark(#111111, #f5f5f5);
--border: light-dark(#e5e5e5, #262626);
--accent: light-dark(#0a0a0a, #ffffff);
}
Langkah 3. Update Tailwind CSS v4 custom theme di @theme block agar mereferensi variable di atas. Hapus semua prefix dark: di komponen yang sudah dilingkupi token.
Langkah 4. Sediakan toggle manual via :has() selector untuk user yang mau override system theme, bukan dengan class JavaScript. Detail teknis ada di dokumen MDN soal light-dark().
Studi Kasus Vetmo: Pet Care Booking
Saat memigrasikan Vetmo (platform booking pet care di Jakarta) dari next-themes ke light-dark(), saya rekam tiga metrik selama 30 hari:
| Metrik | Sebelum | Sesudah | Delta |
|---|---|---|---|
| CSS bundle (gzipped) | 38,4 KB | 29,1 KB | turun 24% |
| LCP p75 mobile 4G | 2,71 detik | 2,53 detik | membaik 180 ms |
| Hydration warning di console | 4 unik per page | 0 | hilang total |
| Theme toggle latency | 70 ms | 22 ms | turun 68% |
Praktik standar yang saya pakai: warna fallback ditulis dulu sebelum light-dark() supaya browser lama tetap dapat warna masuk akal, dan toggle manual cukup pakai [data-theme="dark"] di body kalau user override.
Pertanyaan Umum
Apakah light-dark() jalan tanpa color-scheme di root?
Tidak optimal. Tanpa color-scheme: light dark, browser memperlakukan dokumen sebagai light only sehingga light-dark() selalu kembalikan nilai pertama.
Bagaimana cara support browser lama?
Tulis warna fallback dulu, lalu override dengan light-dark() di baris berikutnya. Browser yang tidak kenal fungsinya akan abaikan baris kedua dan tetap pakai nilai fallback.
Apakah perlu next-themes sama sekali?
Untuk swap warna pure CSS, tidak. Untuk swap konten yang lebih kompleks (gambar berbeda per mode, hide/show section), kombinasi :has([data-theme]) atau next-themes minimalis tetap berguna.
Apakah ini mempengaruhi SEO?
Tidak langsung. Tapi LCP yang membaik dan tanpa CLS dari flash theme berkontribusi positif ke Core Web Vitals yang menjadi sinyal ranking sejak 2021.
Penutup Aplikatif
Migrasi ke light-dark() bukan refactor besar, melainkan penyederhanaan. Mulai dari satu page (biasanya /kontak atau /about) untuk validasi visual, lalu rilis bertahap ke seluruh app. Hasilnya: CSS lebih ramping, hydration lebih bersih, dan dark mode lebih cepat di tangan pengunjung mobile Indonesia.
Artikel Terkait
Website Bisnis
Cara Marketer Indonesia Pasang CSS field-sizing: content di Next.js untuk Form Kontak, Pangkas 6 KB Library Autosize dan Hilangkan Hydration Mismatch SSR di 2026
Pasang field-sizing: content di Next.js untuk auto-resize textarea tanpa JS. Hemat 6 KB autosize, hilangkan hydration mismatch SSR, dan jaga INP stabil di form panjang.
Website Bisnis
Cara Marketer Indonesia Pasang CSS reading-flow di Next.js untuk Layout Flex dan Grid, Sinkronkan Urutan Tab dengan Visual dan Lulus Audit WCAG 2.2 di 2026
Pasang CSS reading-flow di Next.js untuk menyamakan urutan keyboard tab dengan layout visual. Hilangkan tabindex manual dan lulus audit WCAG 2.2 level AA.
Website Bisnis
Cara Marketer Indonesia Pasang HTML popover di Next.js untuk Dropdown Mega-Menu, Pangkas 14 KB Floating UI dan Hilangkan Logika Z-Index Stacking di 2026
Pasang HTML popover di Next.js untuk dropdown mega-menu native. Tutorial pangkas 14 KB Floating UI, hilangkan masalah z-index stacking, dan tingkatkan stabilitas INP. Cocok untuk marketer non-developer.
Butuh website yang benar-benar bekerja?
Hubungi Vito untuk konsultasi gratis 15 menit.
WhatsApp Sekarang