Flash Hitam Saat Navigasi Dashboard — Kisah Debug Color-Scheme yang Membingungkan
⚡ Flash Hitam saat Navigasi — Ternyata Bukan Portfolio Theme
Sebuah kisah debugging yang berawal dari curiga pada tema portfolio, berujung pada pemahaman tentang bagaimana browser menentukan warna latar halaman sebelum CSS sempat dimuat.
Beberapa hari lalu aku mengalami masalah yang cukup mengganggu: setiap kali berpindah menu di dashboard admin — saat menggunakan tema terang — muncul flash hitam sekilas sebelum halaman tampil normal. Flash-nya cepat tapi cukup menyilaukan, seperti kedipan layar yang tidak semestinya.
Awalnya aku curiga pada tema portfolio yang hanya terpasang di adammuiz.com. Pikiran langsung mengarah ke sana karena situs development lokal tidak mengalami masalah yang sama. Kode CMS inti identik, jadi pasti ada yang beda. Dan satu-satunya perbedaan signifikan adalah keberadaan tema portfolio.
"Mungkin tema portfolio meng-inject cookie site-theme=dark," pikirku. Tapi setelah menelusuri semua file tema portfolio — header, footer, theme.json dengan daftar scripts kosong — tidak ada satu baris kode pun yang menyentuh cookie atau localStorage.
🚫 Hipotesis Pertama: Portfolio Theme Ternyata Bersih
Portfolio theme hanya punya HTML statis di header dan footer, satu file CSS, dan nol JavaScript. theme.json-nya bahkan mendeklarasikan "scripts": []. Jadi tidak mungkin dia yang mengatur cookie apapun.
Aku lalu diff semua file yang relevan antara situs development lokal dan adammuiz.com — layout admin, CSS, JS, dashboard/index.php. Semuanya identik 100%. Tidak ada perbedaan kode.
Ini berarti masalahnya bukan di kode, melainkan di faktor eksternal.
🔍 Menemukan Penyebab Sebenarnya
Setelah diff tidak membuahkan hasil, aku melihat lebih dalam ke CSS dashboard. Struktur theme-nya seperti ini:
:root {
color-scheme: light;
--adam-bg: #f9fafb;
}
/* toggle gelap */
html.theme-dark {
color-scheme: dark;
--adam-bg: #071022;
}
/* fallback OS */
@media (prefers-color-scheme: dark) {
html:not(.theme-light):not(.theme-dark) {
color-scheme: dark;
}
}
Di sinilah letak masalahnya. Ketika halaman admin mulai dimuat:
- Tahap 1: Browser mulai parsing HTML. Tag
<html>belum punya class theme apapun. - Tahap 2: Browser melihat CSS eksternal di
<link>— tapi CSS ini belum selesai di-download. - Tahap 3: Karena belum ada class, browser menggunakan
prefers-color-schemedari OS. Kalau OS sedang dark mode — flash hitam terjadi. - Tahap 4: Inline script di
<head>membaca localStorage dan menambahkan classtheme-light. - Tahap 5: CSS selesai di-download.
:root { color-scheme: light; }baru berlaku.
Di situs development lokal (localhost), koneksi server sangat cepat — CSS selesai di-download dalam waktu <1ms, sebelum browser sempat melakukan first paint. Tidak ada jeda, tidak ada flash.
Di adammuiz.com yang menggunakan Cloudflare, CSS harus melewati perjalanan jaringan. Jeda 50–200ms cukup bagi Chrome untuk menampilkan halaman kosong dengan latar belakang gelap (mengikuti preferensi OS). Itulah flash hitam yang terlihat.
Yang menarik: masalah ini tidak memandang tema. Saat OS dalam mode light (Windows default) dan user memilih tema dark di dashboard, yang muncul justru flash putih — browser menampilkan latar OS sebelum CSS dark sempat dimuat. Flash putih ini sama mengganggunya, hanya beda arah. Akar penyebabnya persis sama: browser mengambil keputusan warna kanvas sebelum CSS/JS dari halaman baru tiba.
🧪 Mengapa style.colorScheme via JS Tidak Cukup?
Percobaan pertamaku adalah menambahkan root.style.colorScheme = 'light' di inline script. Secara teori, ini harusnya memberitahu browser untuk menggunakan latar terang sebelum CSS dimuat. Tapi ternyata tidak cukup.
Masalahnya: browser sudah terlanjur memutuskan warna latar sebelum JavaScript dieksekusi. Saat Chrome melihat <html lang="..."> tanpa informasi color-scheme apapun, ia langsung menggunakan preferensi OS sebagai default — terutama saat navigasi penuh antar halaman. JavaScript di <head> datang terlambat.
Di sinilah letak perbedaan krusial: browser menentukan warna latar kanvas di awal parsing HTML, bukan saat CSS/JS selesai diproses. Ini adalah keputusan desain browser untuk memberikan pengalaman yang konsisten dengan preferensi pengguna sedini mungkin.
✅ Solusi: Tiga Lapis Pertahanan
Setelah memahami akar masalahnya, aku menerapkan tiga pendekatan sekaligus:
1. Server-side: Cookie + Meta Tags
Menyimpan preferensi theme ke cookie (tidak hanya localStorage), lalu PHP membaca cookie itu untuk:
- Menambahkan class
theme-lightatautheme-darklangsung di tag<html> - Menyisipkan
<meta name="color-scheme" content="...">— ini yang paling penting, karena meta tag diproses browser sebelum CSS apapun - Menyisipkan
<meta name="theme-color" content="...">— membantu Chrome menentukan warna loading screen saat navigasi
// baca cookie, set server-side
$adamTheme = '';
if (!empty($_COOKIE['adam_theme'])) {
$at = (string)$_COOKIE['adam_theme'];
if ($at === 'dark' || $at === 'light') $adamTheme = $at;
}
$colorScheme = $adamTheme ?: 'light';
$themeColor = $adamTheme === 'dark' ? '#071022' : '#f9fafb';
?>
<html lang="id" class="theme-<?= $adamTheme ?>">
<meta name="color-scheme" content="<?= $colorScheme ?>">
<meta name="theme-color" content="<?= $themeColor ?>">
2. Client-side: Inline Script
Inline script tetap dipertahankan untuk membaca localStorage (antisipasi jika cookie belum ada), dan diperluas untuk:
- Set
root.style.colorSchemesebagai fallback cepat - Sync ke cookie agar navigasi berikutnya server sudah tahu preferensi
- Update
<meta name="theme-color">sesuai tema
3. Theme Toggle JS
Fungsi setTheme() di theme-toggle.js juga diperbarui untuk:
- Set cookie
adam_themesaat user mengganti tema - Update
meta[name="theme-color"]secara real-time - Set
root.style.colorSchemelangsung
📊 Perbandingan Sebelum dan Sesudah
| Skenario | Sebelum | Sesudah |
|---|---|---|
| Nav light theme (OS dark) | ⚡ Flash hitam | ✅ Mulus |
| Nav dark theme | ⚡ Flash putih (kebalikan) | ✅ Mulus |
| First visit (belum ada cookie) | ⚡ Flash hitam | ⚠️ Minimal (default light) |
🔑 Pelajaran Penting
- Jangan hanya andalkan JavaScript untuk mencegah flash warna. Browser memutuskan warna latar kanvas sebelum JS dieksekusi.
- Flash tidak memihak tema. Baik dark-on-light maupun light-on-dark — keduanya sama-sama mengganggu. Solusi server-side dengan
color-schememeta menangani kedua arah sekaligus. <meta name="color-scheme">adalah benteng pertama. Meta tag ini diproses browser lebih awal dari CSS atau JavaScript.- Cookie vs localStorage: localStorage tidak bisa dibaca server. Untuk mencegah flash di navigasi berikutnya, simpan preferensi di cookie juga.
- Cloudflare memperbesar masalah timing. Apa yang tidak terlihat di localhost (latensi <1ms) menjadi jelas terlihat saat ada delay jaringan 50-200ms.
- Diffing adalah teman terbaik debug. Sebelum menyalahkan tema portfolio,
diffmembuktikan kode identik dan mengarahkan pencarian ke faktor eksternal.
📝 Penutup
Masalah flash hitam ini adalah pengingat bahwa pengembangan web modern tidak bisa hanya mengandalkan satu lapis solusi. Interaksi antara server, browser, CSS, JavaScript, dan jaringan menciptakan timing complexity yang perlu dipahami secara holistik.
Kombinasi <meta name="color-scheme">, <meta name="theme-color">, cookie server-side, dan inline script menghasilkan tiga lapis pertahanan yang memastikan dashboard admin tampil mulus dalam kondisi jaringan apapun.
Untuk teman-teman developer yang mengalami masalah serupa: cek dulu color-scheme di CSS kalian. Mungkin jawabannya sesederhana menambahkan satu baris meta tag di <head>.
— Adam Muiz, Juni 2026