Skip to content

Kartu Transparan yang Menghilang di Light Mode

Adityo Guni Waluyo

Kartu bg-card/20 sampai /90 nyaris tak terlihat di light mode karena opacity modifier Tailwind v4 mengkompilasi warna jadi color-mix dengan var token.

Ringkasan

Kartu portofolio pakai bg-card dengan opacity modifier Tailwind yang dikompilasi jadi color-mix terhadap variabel --card, jadi hasilnya tergantung tema. Saat latar light mode dibuat terang, campuran putih transparan menyatu dengan latar dan kartu jadi tak terlihat, padahal dark mode aman karena kontrasnya beda. Solusinya override CSS spesifik light mode yang memaksa background solid plus bayangan tipis.

Deploy ke production, saya buka situs di Chrome, pindah ke light mode, dan yang terlihat cuma latar #f8fafc yang polos. Kartu-kartu portofolio yang di dark mode tampil jelas itu nyaris tak terlihat. Elemennya ada, border-nya ada, tapi permukaannya lenyap ke dalam latar.

Saya buka DevTools, inspect salah satu kartu. Kelasnya bg-card/20 sampai bg-card/90, semua pakai opacity modifier Tailwind. Yang bikin bingung, variabel --card nilainya benar, putih hex bersih. Latar halaman juga putih kehijauan muda. Jadi kartu putih di atas latar hampir putih, dicampur opacity 20 sampai 90 persen. Hasilnya kartu hantu: ada di DOM, hilang di mata.

Saya cek juga kondisi sebelumnya. Kartu-kartu itu memakai permukaan semi-transparan supaya aurora background di belakangnya tembus sedikit, memberi kesan glass. Trik ini bekerja di dark mode karena latar gelap kontras dengan campuran putih transparan. Begitu latar jadi terang, campuran itu malah menyatu dengan latar.

Dugaan pertama saya, variabel --card salah set. Mungkin salah hex, mungkin ke-copy dari palet dark mode. Saya buka berkas frontend/src/styles/globals.css, cek ulang: putih juga. Bukan masalah token.

Kenapa di dark mode semua baik-baik saja, tapi di light mode hancur? Kalau warnanya salah, harusnya dua-duanya rusak.

Opacity Modifier Bukan Sekadar Alpha

Saya telusuri source code Tailwind v4. Ternyata opacity modifier tidak menulis alpha channel langsung. Fungsi withAlpha() di packages/tailwindcss/src/utilities.ts mengkompilasi bg-card/50 menjadi deklarasi color-mix [1], seperti pada pola berikut:

/* hasil kompilasi Tailwind v4 untuk bg-card/50 */
background-color: color-mix(in oklab, var(--card) 50%, transparent);

Dokumentasi resmi Tailwind memang memasarkan modifier ini sebagai cara mengatur opacity warna background [2]. Dan memang benar, secara teknis itulah yang terjadi: mencampur warna dengan transparent memberi efek alpha multiplier, artinya hasil akhirnya adalah warna kartu yang sama dengan tingkat tembus pandang 50 persen.

Masalahnya bukan di sana. Masalahnya, nilai yang dicampur adalah var(--card) sebuah CSS variable yang menunjuk ke token tema. Di dark mode variabel itu menunjuk ke warna gelap, di light mode ke putih. Satu kelas bg-card/50 yang sama menghasilkan dua warna computed berbeda tergantung tema. Ketika saya merombak tema light menjadi latar terang solid, semua campuran semi-transparan itu ikut berubah makna tanpa saya sentuh satu kelas pun.

Konsekuensi matematisnya sederhana. Putih 20 persen di atas #f8fafc menghasilkan warna yang hanya berbeda beberapa poin dari latar. Campuran 90 persen masih terlalu dekat. MDN merangkum batas ini dengan tegas: color-mix() tidak bisa mengubah warna semi-transparan menjadi opak penuh; untuk itu warnanya harus diganti langsung, bukan dicampur [3]. Modifier mengatur tembus pandang, bukan kontras.

Fix yang Dipilih

Opsi yang terbuka ada tiga. Pertama, ubah desain kartu supaya tak lagi bergantung pada permukaan transparan. Kedua, ganti token --card ke format rgb dengan alpha eksplisit. Ketiga, paksa permukaan kartu jadi solid di light mode lewat override CSS.

Saya pilih yang ketiga karena paling sempit cakupannya. Override light mode untuk kelas bg-card dari tingkat 20 sampai 90 diarahkan ke background-color: var(--card) !important, plus bayangan tipis keabu-abuan supaya kartu tetap terangkat dari latar:

.light .bg-card\/50 {
  background-color: var(--card) !important;
  box-shadow: 0 1px 3px rgb(15 23 42 / 0.06), 0 1px 2px rgb(15 23 42 / 0.04);
}

Override ini menang atas utility asli karena selektornya dua kelas, .light gabung bg-card/50, yang lebih spesifik daripada satu kelas utility. Tanda !important di commit asli saya pertahankan sebagai pengaman, supaya aturan ini tetap menang bila suatu saat urutan deklarasi berubah. Kenapa bukan ubah token ke rgb? Karena token itu dipakai banyak komponen di dua tema; mengubah nilai default berarti mengubah kontrak semua pemakainya. Override spesifik light mode hanya menyentuh satu file, satu blok, dan dark mode tidak tersentuh sama sekali.

Pelajaran yang saya bawa: opacity modifier Tailwind bukan kontrak warna final ketika tokennya CSS variable. Yang dijanjikan adalah rumus campuran, bukan hasil. Rumus yang sama bisa tampil bagus di satu tema dan menghilang di tema lain. Kalau permukaan kartu memang harus terlihat, tulis warna solidnya secara eksplisit, lalu pisahkan kartu dari latar dengan bayangan, bukan dengan alpha. Perbaikan ini juga kelanjutan dari pengalaman serupa waktu [menyeting ulang warna accent yang pudar di light mode](/id/blog/accent-mint-dua-mode): tema gelap memaafkan banyak pilihan warna, tema terang tidak.

Sumber

Artikel terkait