<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>CSS on kenji.blog</title><link>http://kenji.blog/id/categories/css/</link><description>Recent content in CSS on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>id</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 12:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/id/categories/css/index.xml" rel="self" type="application/rss+xml"/><item><title>Poin-poin Desain CSS untuk Menerapkan Mode Gelap di Blog</title><link>http://kenji.blog/id/p/dark-mode-css-design-patterns/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/id/p/dark-mode-css-design-patterns/</guid><description>&lt;img src="http://kenji.blog/p/dark-mode-css-design-patterns/img/eyecatch.jpg" alt="Featured image of post Poin-poin Desain CSS untuk Menerapkan Mode Gelap di Blog" />&lt;p>Dalam pengembangan web modern, dukungan mode gelap (Dark Mode) telah berubah dari sekadar &amp;ldquo;fitur tambahan yang bagus (Nice to have)&amp;rdquo; menjadi &amp;ldquo;persyaratan wajib (Must have)&amp;rdquo; untuk meningkatkan pengalaman pengguna (UX). Khususnya untuk media yang membutuhkan waktu baca yang lama seperti blog dan situs dokumentasi, dukungan mode gelap sangatlah penting karena dapat mengurangi kelelahan mata pengguna dan menghemat konsumsi baterai perangkat.&lt;/p>
&lt;p>Pada artikel ini, saya akan membahas secara mendalam dari sudut pandang seorang frontend engineer mengenai tantangan teknis yang tidak dapat dihindari saat mengimplementasikan mode gelap di blog, beserta poin-poin desain CSS dengan maintainability yang tinggi. Saya akan mencakup semuanya tentang implementasi mode gelap, mulai dari penggunaan CSS Custom Properties (Variabel CSS), kontrol JavaScript tingkat lanjut dan integrasi SSR untuk mencegah FOUC (Flash of Unstyled Content), desain warna (RGB, HSL, dan OKLCH terbaru) untuk memastikan aksesibilitas (WCAG 2.1 AAA), hingga contoh kode praktis menggunakan Tailwind CSS.&lt;/p>
&lt;hr>
&lt;h2 id="1-dasar-dasar-desain-tema-dengan-css-custom-properties-variabel-css">1. Dasar-dasar Desain Tema dengan CSS Custom Properties (Variabel CSS)
&lt;/h2>&lt;p>Dalam mengimplementasikan mode gelap, pendekatan yang paling standar dan kuat saat ini adalah memanfaatkan &lt;strong>CSS Custom Properties (Variabel CSS)&lt;/strong>. Berbeda dengan variabel preprocessor CSS seperti Sass (&lt;code>$color&lt;/code>) yang diselesaikan secara statis saat kompilasi, variabel CSS dapat diselesaikan dan ditimpa secara dinamis pada runtime browser. Hal ini memungkinkan kita untuk mengubah warna keseluruhan halaman secara instan hanya dengan beralih kelas melalui JavaScript.&lt;/p>
&lt;h3 id="11-mendefinisikan-tema-warna-dasar">1.1 Mendefinisikan Tema Warna Dasar
&lt;/h3>&lt;p>Pertama, kita mendefinisikan palet warna untuk mode terang (default) menggunakan pseudo-class &lt;code>:root&lt;/code>. Kemudian, pola desain utamanya adalah menimpa variabel-variabel tersebut ketika atribut seperti &lt;code>[data-theme='dark']&lt;/code> (atau kelas &lt;code>.dark&lt;/code>) diterapkan.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-css" data-lang="css">&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* Definisi variabel mode terang (default) */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">:&lt;/span>&lt;span class="nd">root&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-bg-primary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#ffffff&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-bg-secondary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#f3f4f6&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-text-primary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#111827&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-text-secondary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#4b5563&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-accent&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#3b82f6&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-border&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#e5e7eb&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* Menimpa variabel saat mode gelap */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>&lt;span class="nt">data-theme&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;dark&amp;#39;&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-bg-primary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#111827&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-bg-secondary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#1f2937&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-text-primary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#f9fafb&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-text-secondary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#9ca3af&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-accent&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#60a5fa&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-border&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#374151&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* Penerapan aktual */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">body&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">background-color&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">var&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="kc">color&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">bg&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">primary&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">color&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">var&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="kc">color&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="kc">text&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">primary&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">transition&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">background-color&lt;/span> &lt;span class="mf">0.3&lt;/span>&lt;span class="kt">s&lt;/span> &lt;span class="kc">ease&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">color&lt;/span> &lt;span class="mf">0.3&lt;/span>&lt;span class="kt">s&lt;/span> &lt;span class="kc">ease&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">a&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">color&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">var&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="kc">color&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">accent&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dengan memisahkan secara sempurna antara spesifikasi tata letak atau tipografi dan spesifikasi warna (tema) seperti ini, kemudahan pemeliharaan (maintainability) CSS akan meningkat drastis.&lt;/p>
&lt;h3 id="12-memanfaatkan-media-prefers-color-scheme-dark">1.2 Memanfaatkan @media (prefers-color-scheme: dark)
&lt;/h3>&lt;p>Jika mode gelap telah diatur di tingkat OS, maka secara otomatis menerapkan tema gelap sejak kunjungan pertama situs web sangat dianjurkan dari sudut pandang UX. Hal ini dapat dicapai melalui media query &lt;code>@media (prefers-color-scheme: dark)&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-css" data-lang="css">&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* Fallback ketika pengaturan sistem OS adalah mode gelap */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">@&lt;/span>&lt;span class="k">media&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nt">prefers-color-scheme&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nt">dark&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">:&lt;/span>&lt;span class="nd">root&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="nd">not&lt;/span>&lt;span class="o">([&lt;/span>&lt;span class="nt">data-theme&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;light&amp;#39;&lt;/span>&lt;span class="o">])&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-bg-primary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#111827&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-bg-secondary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#1f2937&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-text-primary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#f9fafb&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-text-secondary&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#9ca3af&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-accent&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#60a5fa&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--color-border&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#374151&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dengan penulisan ini, variabel akan ditimpa untuk menghormati pengaturan mode gelap pada OS, kecuali jika pengguna secara eksplisit memilih mode terang (&lt;code>data-theme='light'&lt;/code>).&lt;/p>
&lt;hr>
&lt;h2 id="2-memahami-ruang-warna-dan-aksesibilitas-wcag-21-aaa">2. Memahami Ruang Warna dan Aksesibilitas (WCAG 2.1 AAA)
&lt;/h2>&lt;p>Dalam desain warna mode gelap, sekadar &amp;ldquo;membuat latar belakang hitam dan teks putih&amp;rdquo; tidaklah cukup. Jika kontras terlalu tinggi, dapat menyebabkan halation dan justru sulit dibaca; sedangkan jika kontras terlalu rendah, visibilitasnya akan berkurang. Web Content Accessibility Guidelines (WCAG) mendefinisikan rasio kontras secara ketat untuk memastikan visibilitas.&lt;/p>
&lt;h3 id="21-rumus-perhitungan-rasio-kontras-wcag">2.1 Rumus Perhitungan Rasio Kontras WCAG
&lt;/h3>&lt;p>Rasio Kontras (Contrast Ratio) $CR$ dalam WCAG didefinisikan sebagai berikut menggunakan Relative Luminance (Luminansi Relatif) dari warna latar belakang dan warna latar depan.&lt;/p>
$$CR = \frac{L_{lighter} + 0.05}{L_{darker} + 0.05}$$&lt;p>Di sini, $L_{lighter}$ adalah luminansi relatif dari warna yang lebih terang, dan $L_{darker}$ adalah luminansi relatif dari warna yang lebih gelap (rentang nilainya dari 0.0 hingga 1.0). Untuk mencapai WCAG 2.1 level AAA, rasio kontras yang diperlukan adalah &lt;strong>minimal 7:1&lt;/strong> untuk teks biasa, dan &lt;strong>minimal 4.5:1&lt;/strong> untuk teks berukuran besar.&lt;/p>
&lt;p>Luminansi relatif $L$ dihitung dari nilai RGB pada ruang warna sRGB dengan rumus yang rumit berikut ini:&lt;/p>
$$L = 0.2126 \times R + 0.7152 \times G + 0.0722 \times B$$&lt;p>Setiap komponen ($R, G, B$) menggunakan nilai normalisasi yang didapat dengan membagi nilai 8-bit asli ($R_{sRGB}$) dengan 255, dan melakukan transformasi berikut untuk menyelesaikan koreksi gamma:&lt;/p>
$$
R, G, B =
\begin{cases}
\frac{C_{sRGB}}{12.92} &amp; \text{jika } C_{sRGB} \le 0.03928 \\
\left( \frac{C_{sRGB} + 0.055}{1.055} \right)^{2.4} &amp; \text{lainnya}
\end{cases}
$$&lt;p>Melakukan perhitungan ini secara manual sangatlah sulit, namun dengan memanfaatkan alat desain warna, kita dapat secara mekanis memilih warna yang memenuhi rasio kontras 7:1 ($CR \ge 7.0$).&lt;/p>
&lt;h3 id="22-hsl-vs-rgb-vs-oklch">2.2 HSL vs RGB vs OKLCH
&lt;/h3>&lt;p>Saat membuat palet warna, RGB dan HSL dulunya merupakan arus utama. Namun, keduanya memiliki kelemahan yang signifikan dalam hal &amp;ldquo;keseragaman persepsi&amp;rdquo; (perceptual uniformity).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>RGB&lt;/strong>: Berdasarkan tiga warna primer cahaya mekanis, sehingga menyulitkan manusia untuk secara intuitif melakukan penyesuaian seperti &amp;ldquo;buat lebih terang&amp;rdquo; atau &amp;ldquo;buat lebih gelap&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>HSL&lt;/strong>: Menggunakan warna (Hue), saturasi (Saturation), dan kecerahan (Lightness). Namun, &amp;ldquo;Lightness (L)&amp;rdquo; dalam HSL tidak sesuai dengan persepsi kecerahan pada mata manusia. Misalnya, warna kuning murni dan biru murni dengan Lightness 50% di HSL secara numerik memiliki kecerahan yang sama, tetapi di mata manusia warna kuning terlihat jauh lebih terang.&lt;/li>
&lt;li>&lt;strong>OKLCH&lt;/strong>: Ruang warna terbaru yang diperkenalkan pada CSS Color Module Level 4. Terdiri dari Lightness (kecerahan perseptual), Chroma (saturasi warna), dan Hue (corak warna), serta &lt;strong>sepenuhnya selaras dengan karakteristik visual manusia (keseragaman perseptual)&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;p>Dengan menggunakan OKLCH, meskipun kita mengubah corak warna (Hue), kecerahan perseptual (Lightness) akan tetap terjaga. Hal ini membuat pembuatan palet warna untuk mode gelap menjadi sangat dapat diprediksi dan aman.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-css" data-lang="css">&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* Contoh definisi variabel CSS menggunakan OKLCH */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">:&lt;/span>&lt;span class="nd">root&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">/* Kecerahan dasar mode terang tinggi, dengan saturasi yang direndahkan */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--bg-base&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">oklch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">0.98&lt;/span> &lt;span class="mf">0.01&lt;/span> &lt;span class="mi">250&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--text-base&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">oklch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">0.25&lt;/span> &lt;span class="mf">0.02&lt;/span> &lt;span class="mi">250&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--primary-brand&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">oklch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">0.65&lt;/span> &lt;span class="mf">0.15&lt;/span> &lt;span class="mi">250&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>&lt;span class="nt">data-theme&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;dark&amp;#34;&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">/* Pada mode gelap, cukup balikkan kecerahan untuk menjaga kontras persepsi */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--bg-base&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">oklch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">0.20&lt;/span> &lt;span class="mf">0.02&lt;/span> &lt;span class="mi">250&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--text-base&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">oklch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">0.95&lt;/span> &lt;span class="mf">0.01&lt;/span> &lt;span class="mi">250&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">--primary-brand&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">oklch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">0.75&lt;/span> &lt;span class="mf">0.15&lt;/span> &lt;span class="mi">250&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c">/* Dibuat sedikit lebih terang untuk visibilitas mode gelap */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dengan mengadopsi OKLCH seperti ini, kita dapat membangun logika sederhana untuk memastikan rasio kontras yang konsisten (standar WCAG AAA) pada beberapa tema.&lt;/p>
&lt;hr>
&lt;h2 id="3-mencegah-fouc-flash-of-unstyled-content-dan-ssr-hydration">3. Mencegah FOUC (Flash of Unstyled Content) dan SSR Hydration
&lt;/h2>&lt;p>Masalah yang paling merepotkan pengembang saat mendukung mode gelap adalah masalah kedipan layar yang disebut &lt;strong>FOUC (Flash of Unstyled Content)&lt;/strong>.&lt;/p>
&lt;h3 id="31-jebakan-peralihan-tema-dengan-client-side-js">3.1 Jebakan Peralihan Tema dengan Client-side JS
&lt;/h3>&lt;p>Pada SPA seperti React atau Vue (atau situs statis yang menggunakan SSG), sangat umum untuk menyimpan pengaturan pengguna di &lt;code>localStorage&lt;/code>, kemudian membacanya dan mengganti tema menggunakan JavaScript. Namun, jika ini dilakukan di dalam React &lt;code>useEffect&lt;/code> misalnya, masalah berikut akan muncul:&lt;/p>
&lt;ol>
&lt;li>Browser merender HTML/CSS mode terang.&lt;/li>
&lt;li>Bundle JS dimuat dan dieksekusi.&lt;/li>
&lt;li>Membaca pengaturan &lt;code>dark&lt;/code> dari &lt;code>localStorage&lt;/code>.&lt;/li>
&lt;li>Kelas &lt;code>dark&lt;/code> ditambahkan ke HTML, dan layar tiba-tiba menjadi gelap (berkedip).&lt;/li>
&lt;/ol>
&lt;h3 id="32-solusi-pencegahan-fouc-yang-sempurna-menggunakan-cookie-dan-ssr">3.2 Solusi Pencegahan FOUC yang Sempurna: Menggunakan Cookie dan SSR
&lt;/h3>&lt;p>Praktik terbaik untuk sepenuhnya mencegah FOUC dan kesalahan hidrasi (hydration error) adalah dengan &lt;strong>menyimpan pengaturan tema pengguna di &lt;code>document.cookie&lt;/code>, kemudian merender HTML yang sudah disertai kelas tema secara tepat pada tahap Server-side Rendering (SSR)&lt;/strong>.&lt;/p>
&lt;p>Diagram urutan berikut ini menunjukkan alur ideal inisialisasi tema menggunakan Cookie.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant User as &amp;#34;Pengguna&amp;#34;
participant Browser as &amp;#34;Browser OS&amp;#34;
participant Server as &amp;#34;Server SSR&amp;#34;
participant DOM as &amp;#34;Klien DOM&amp;#34;
User-&amp;gt;&amp;gt;Browser: &amp;#34;Minta Halaman&amp;#34;
Browser-&amp;gt;&amp;gt;Server: &amp;#34;Permintaan GET dengan Cookie (theme=dark)&amp;#34;
Server--&amp;gt;&amp;gt;Browser: &amp;#34;Kembalikan HTML dengan &amp;lt;html data-theme=&amp;#39;dark&amp;#39;&amp;gt;&amp;#34;
Browser-&amp;gt;&amp;gt;DOM: &amp;#34;Render HTML Awal (Tanpa FOUC)&amp;#34;
DOM-&amp;gt;&amp;gt;DOM: &amp;#34;Eksekusi Skrip Hidrasi&amp;#34;
alt &amp;#34;Cookie tidak ada (Kunjungan Pertama)&amp;#34;
DOM-&amp;gt;&amp;gt;Browser: &amp;#34;Periksa OS prefers-color-scheme&amp;#34;
Browser--&amp;gt;&amp;gt;DOM: &amp;#34;Hasil matchMedia (misalnya dark)&amp;#34;
DOM-&amp;gt;&amp;gt;DOM: &amp;#34;Atur data-theme=&amp;#39;dark&amp;#39; melalui skrip inline pemblokiran&amp;#34;
end
&lt;/pre>
&lt;h3 id="33-garis-pertahanan-dengan-skrip-inline-untuk-situs-statis-tanpa-cookie">3.3 Garis Pertahanan dengan Skrip Inline (Untuk Situs Statis tanpa Cookie)
&lt;/h3>&lt;p>Untuk blog yang hanya menggunakan SSG (Static Site Generation) dan SSR tidak dimungkinkan (misalnya eksport statis pada Hugo, Gatsby, atau Astro), teknik menyisipkan skrip JavaScript inline yang bersifat memblokir (blocking) di dalam tag &lt;code>&amp;lt;head&amp;gt;&lt;/code> menjadi hal yang wajib dilakukan untuk menambahkan kelas tepat sebelum DOM dirender.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Tempatkan di bagian paling akhir dalam &amp;lt;head&amp;gt; --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">var&lt;/span> &lt;span class="nx">localTheme&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">localStorage&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">getItem&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;theme&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">var&lt;/span> &lt;span class="nx">osTheme&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">window&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">matchMedia&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;(prefers-color-scheme: dark)&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">matches&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="s1">&amp;#39;dark&amp;#39;&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;light&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">var&lt;/span> &lt;span class="nx">theme&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">localTheme&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="nx">osTheme&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">document&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">documentElement&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">setAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;data-theme&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">theme&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Skrip kecil ini akan memblokir rendering browser dan langsung dieksekusi, sehingga atribut &lt;code>data-theme&lt;/code> sudah tersusun pada saat layar dirender, mencegah sepenuhnya kedipan layar (FOUC).&lt;/p>
&lt;hr>
&lt;h2 id="4-pendekatan-implementasi-pada-tailwind-css-dan-raw-scsscss">4. Pendekatan Implementasi pada Tailwind CSS dan Raw SCSS/CSS
&lt;/h2>&lt;p>Saat mengintegrasikan mode gelap ke dalam proyek nyata, kita perlu memahami pendekatan untuk setiap tools yang digunakan.&lt;/p>
&lt;h3 id="41-mode-gelap-pada-tailwind-css">4.1 Mode Gelap pada Tailwind CSS
&lt;/h3>&lt;p>Tailwind CSS menyediakan varian &lt;code>dark:&lt;/code> secara default, membuat implementasi mode gelap menjadi sangat mudah. Atur properti &lt;code>darkMode&lt;/code> dalam file konfigurasi (&lt;code>tailwind.config.js&lt;/code>).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// tailwind.config.js
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">module&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">exports&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// &amp;#39;media&amp;#39; (Bergantung pada pengaturan OS) atau &amp;#39;class&amp;#39; (Bisa dialihkan secara manual)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">darkMode&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;class&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">theme&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">extend&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">colors&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cm">/* Memperluas palet warna Tailwind dengan variabel CSS */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">primary&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;rgb(var(--color-primary) / &amp;lt;alpha-value&amp;gt;)&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">background&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;rgb(var(--color-background) / &amp;lt;alpha-value&amp;gt;)&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Di sisi HTML, kita hanya perlu menambahkan kelas seperti berikut.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h1&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text-2xl font-bold&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Hello World&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h1&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;mt-2&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Tailwind makes dark mode incredibly easy.&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Akan tetapi, menulis &lt;code>dark:bg-xxx&lt;/code> pada setiap elemen dapat menyebabkan komponen membengkak. Pada aplikasi atau blog berskala besar, disarankan menggunakan pendekatan hibrida (desain warna semantik), di mana &lt;strong>basisnya menggunakan variabel CSS, dan Tailwind akan merujuk ke variabel CSS tersebut&lt;/strong>.&lt;/p>
&lt;p>Berikut adalah diagram kelas yang menunjukkan pewarisan variabel CSS dan lapisan penerapannya.&lt;/p>
&lt;pre class="mermaid">
classDiagram
class GlobalCSSVariables {
&amp;#34;--color-brand-500&amp;#34;
&amp;#34;--color-gray-900&amp;#34;
}
class SemanticVariables {
&amp;#34;--bg-primary&amp;#34;
&amp;#34;--text-base&amp;#34;
&amp;#34;--accent&amp;#34;
}
class TailwindConfig {
&amp;#34;theme.colors.background&amp;#34;
&amp;#34;theme.colors.primary&amp;#34;
}
class UIComponents {
&amp;#34;class=&amp;#39;bg-background text-primary&amp;#39;&amp;#34;
}
GlobalCSSVariables &amp;lt;|-- SemanticVariables : &amp;#34;:root &amp;amp; .dark&amp;#34;
SemanticVariables &amp;lt;|-- TailwindConfig : &amp;#34;tailwind.config.js&amp;#34;
TailwindConfig &amp;lt;.. UIComponents : &amp;#34;Menerapkan Kelas Utilitas&amp;#34;
&lt;/pre>
&lt;h3 id="42-implementasi-pada-raw-scsscss-memanfaatkan-mixin">4.2 Implementasi pada Raw SCSS/CSS (Memanfaatkan Mixin)
&lt;/h3>&lt;p>Dalam proyek yang tidak menggunakan Tailwind dan menulis SCSS sendiri, gunakan &lt;code>@mixin&lt;/code> untuk merangkum gaya (style) pada mode gelap.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-scss" data-lang="scss">&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/* Definisi SCSS Mixin */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">@mixin&lt;/span>&lt;span class="nf"> dark-mode&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cm">/* Mendukung atribut [data-theme=&amp;#39;dark&amp;#39;] dan pengaturan OS */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">[&lt;/span>&lt;span class="nt">data-theme&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;dark&amp;#39;&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="k">&amp;amp;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">@content&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">@media&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">prefers-color-scheme&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="ni">dark&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">:root:not&lt;/span>&lt;span class="o">([&lt;/span>&lt;span class="nt">data-theme&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;light&amp;#39;&lt;/span>&lt;span class="o">])&lt;/span> &lt;span class="k">&amp;amp;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">@content&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/* Contoh Penggunaan */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nc">.card&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">background-color&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="mh">#ffffff&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">color&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="mh">#333333&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">border&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="kt">px&lt;/span> &lt;span class="ni">solid&lt;/span> &lt;span class="mh">#eeeeee&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">@include&lt;/span>&lt;span class="nd"> dark-mode&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">background-color&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="mh">#1a202c&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">color&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="mh">#e2e8f0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">border-color&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="mh">#2d3748&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Metode ini memang intuitif, tetapi rentan menyebabkan pembengkakan ukuran file CSS hasil kompilasi (karena media query disalin ke setiap selector). Karenanya, tren saat ini bergeser ke desain berbasis variabel CSS (Custom Properties).&lt;/p>
&lt;hr>
&lt;h2 id="5-optimalisasi-gambar-image-dan-svg-pada-mode-gelap">5. Optimalisasi Gambar (Image) dan SVG pada Mode Gelap
&lt;/h2>&lt;p>Meskipun desain warna pada teks atau latar belakang sudah selesai, jika gambar atau ikon (SVG) yang ditempatkan sebagai konten tetap pada pengaturan mode terang, tampilannya akan terlihat sangat menyilaukan dan menonjol ketika dilihat dalam mode gelap. Oleh karena itu, optimalisasi bagian ini sangatlah penting.&lt;/p>
&lt;h3 id="51-filter-css-untuk-menurunkan-kecerahan-gambar">5.1 Filter CSS untuk Menurunkan Kecerahan Gambar
&lt;/h3>&lt;p>Gambar bitmap seperti foto, jika ditampilkan apa adanya saat mode gelap, terkadang terlalu menyilaukan. Dengan menggunakan properti &lt;code>filter&lt;/code> pada CSS untuk sedikit menurunkan kecerahan (brightness) dan menaikkan kontras (contrast) gambar, kita dapat membaurkan gambar secara alami ke dalam UI mode gelap.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-css" data-lang="css">&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>&lt;span class="nt">data-theme&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;dark&amp;#39;&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="nt">img&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="nd">not&lt;/span>&lt;span class="o">([&lt;/span>&lt;span class="nt">src&lt;/span>&lt;span class="o">*=&lt;/span>&lt;span class="s2">&amp;#34;.svg&amp;#34;&lt;/span>&lt;span class="o">])&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">/* Turunkan kecerahan, tingkatkan kontras sedikit */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">filter&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">brightness&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">0.8&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nb">contrast&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">1.1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">transition&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">filter&lt;/span> &lt;span class="mf">0.3&lt;/span>&lt;span class="kt">s&lt;/span> &lt;span class="kc">ease&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>&lt;span class="nt">data-theme&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;dark&amp;#39;&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="nt">img&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="nd">hover&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">/* Kembalikan ke kecerahan asli saat hover (ketika pengguna ingin melihat detailnya) */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">filter&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">brightness&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nb">contrast&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="52-menyajikan-gambar-berbeda-dengan-tag-picture">5.2 Menyajikan Gambar Berbeda dengan Tag &lt;code>&amp;lt;picture&amp;gt;&lt;/code>
&lt;/h3>&lt;p>Gambar logo atau ilustrasi penjelasan (seperti JPEG dengan latar belakang putih pekat) tidak bisa hanya diandalkan dengan filter. Dalam kasus seperti ini, solusi tepat adalah menyajikan file gambar yang berbeda untuk mode gelap menggunakan elemen HTML &lt;code>&amp;lt;picture&amp;gt;&lt;/code> beserta media query.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">picture&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- Tampilkan ini untuk pengguna dengan pengaturan OS mode gelap --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">source&lt;/span> &lt;span class="na">srcset&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;/img/logo-dark.png&amp;#34;&lt;/span> &lt;span class="na">media&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;(prefers-color-scheme: dark)&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- Default (Mode terang) --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">img&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;/img/logo-light.png&amp;#34;&lt;/span> &lt;span class="na">alt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;Logo situs&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">picture&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;em>Catatan: Metode ini hanya bergantung pada pengaturan OS, sehingga tidak tersinkronisasi jika perubahan mode dilakukan manual (seperti lewat &lt;code>localStorage&lt;/code>). Jika fitur peralihan manual diterapkan, Anda perlu mengubah &lt;code>src&lt;/code> gambar secara dinamis dengan JS atau beralih kelas CSS dengan &lt;code>display: none&lt;/code>.&lt;/em>&lt;/p>
&lt;h3 id="53-dukungan-currentcolor-untuk-ikon-svg">5.3 Dukungan &lt;code>currentColor&lt;/code> untuk Ikon SVG
&lt;/h3>&lt;p>Untuk ikon SVG inline, cara paling cerdas adalah menautkan warna pengisian dengan warna teks dari elemen induknya. Cukup tentukan &lt;code>currentColor&lt;/code> pada atribut &lt;code>fill&lt;/code> atau &lt;code>stroke&lt;/code> SVG.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Nilai dari properti color CSS (seperti var(--text-primary)) akan diterapkan secara otomatis --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">svg&lt;/span> &lt;span class="na">viewBox&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;0 0 24 24&amp;#34;&lt;/span> &lt;span class="na">fill&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;currentColor&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">path&lt;/span> &lt;span class="na">d&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;M12 2L2 22h20L12 2z&amp;#34;&lt;/span> &lt;span class="p">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">svg&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dengan cara ini, saat beralih ke mode gelap dan warna font pada elemen induk berubah ke nuansa putih, ikon SVG juga akan otomatis berubah mengikuti warna putih tersebut.&lt;/p>
&lt;hr>
&lt;h2 id="6-kesimpulan-menuju-desain-mode-gelap-yang-berkelanjutan">6. Kesimpulan: Menuju Desain Mode Gelap yang Berkelanjutan
&lt;/h2>&lt;p>Untuk mengimplementasikan mode gelap berkualitas tinggi pada blog atau aplikasi web, desain CSS yang mencakup poin-poin berikut ini sangatlah esensial.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Memanfaatkan CSS Custom Properties&lt;/strong>: Hindari hardcode pengaturan warna, melainkan abstraksikan ke dalam penamaan variabel semantik (misal: &lt;code>--bg-primary&lt;/code>).&lt;/li>
&lt;li>&lt;strong>Mengadopsi Ruang Warna OKLCH&lt;/strong>: Rancang secara logis pada ruang warna yang seragam secara perseptual untuk mencapai rasio kontras dengan aksesibilitas tinggi (minimal 7:1) yang memenuhi WCAG 2.1 AAA.&lt;/li>
&lt;li>&lt;strong>Mencegah FOUC Sepenuhnya&lt;/strong>: Hilangkan kedipan layar sepenuhnya saat pertama dimuat menggunakan integrasi SSR dan Cookie, atau melalui skrip inline pemblokiran di dalam &lt;code>&amp;lt;head&amp;gt;&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Optimalisasi Media dan Aset&lt;/strong>: Manfaatkan &lt;code>filter: brightness()&lt;/code>, &lt;code>currentColor&lt;/code>, dan tag &lt;code>&amp;lt;picture&amp;gt;&lt;/code> agar elemen selain teks juga selaras dengan tema gelap.&lt;/li>
&lt;/ol>
&lt;p>Bukan sekadar &amp;ldquo;membalik warna&amp;rdquo;, melainkan penerapan dengan detail mendalam inilah yang menjadi syarat sebuah blog modern. Blog yang dicintai pengguna untuk waktu yang lama dan mampu menyuguhkan pengalaman membaca (reading experience) yang hebat serta tidak membuat mata cepat lelah. Bagi para pengembang yang ingin memperkenalkan mode gelap ke depannya, silakan jadikan pola desain dari artikel ini sebagai referensi yang andal.&lt;/p></description></item></channel></rss>