Tutorial: CSS Variables & Membuat Theme Switcher Keren (Light/Dark Mode)

Tutorial: CSS Variables & Membuat Theme Switcher Keren (Light/Dark Mode)

Tutorial: CSS Variables & Membuat Theme Switcher Keren (Light/Dark Mode)

Novian Hidayat
2025-06-14

Kuasai CSS Variables (Custom Properties) untuk membuat website yang lebih dinamis dan mudah dikelola! Pelajari sintaks, keuntungan, dan cara menggunakannya untuk membangun theme switcher (mode terang/gelap) dengan JavaScript.

Tutorial: Mengenal CSS Variables dan Cara Menggunakannya untuk Membuat Theme Switcher (Mode Terang/Gelap)

Pernahkah Anda ingin mengubah skema warna atau font di seluruh website Anda hanya dengan mengubah satu baris kode? Atau mungkin Anda ingin memberikan pengguna pilihan untuk beralih antara mode terang (light mode) dan mode gelap (dark mode)? Inilah saatnya Anda berkenalan dengan CSS Variables, atau yang secara resmi dikenal sebagai CSS Custom Properties.

Dalam tutorial ini, kita akan mempelajari apa itu CSS Variables, mengapa mereka sangat berguna, dan bagaimana cara menggunakannya untuk membangun fitur populer: theme switcher atau pengalih tema.

1. Pendahuluan

Apa itu CSS Variables (--nama-variabel)?

CSS Variables memungkinkan Anda mendefinisikan nilai-nilai yang dapat digunakan kembali di seluruh stylesheet Anda. Bayangkan mereka seperti variabel dalam bahasa pemrograman, tetapi untuk CSS. Anda bisa mendefinisikan sebuah variabel, misalnya --primary-color, dan kemudian menggunakan nilai variabel tersebut di berbagai properti CSS.

Keuntungan Menggunakan CSS Variables

Dibandingkan menulis nilai secara langsung (nilai tetap atau hardcoded values), CSS Variables menawarkan banyak keuntungan:

  • Reusable (Dapat Digunakan Kembali): Definisikan sekali, gunakan berkali-kali. Ini mengurangi pengulangan kode.
  • Konsisten: Memastikan konsistensi visual di seluruh situs. Jika warna primer Anda berubah, Anda hanya perlu mengubahnya di satu tempat.
  • Mudah Diubah Secara Global (dan Lokal): Perubahan pada nilai variabel akan langsung diterapkan ke semua elemen yang menggunakannya. Anda juga bisa menimpa (override) variabel untuk cakupan tertentu.
  • Dinamis dengan JavaScript: Nilai CSS Variables bisa dibaca dan diubah menggunakan JavaScript, membuka pintu untuk fitur interaktif seperti theme switcher.
  • Sangat Berguna untuk Theming: Ideal untuk membuat tema terang/gelap, atau bahkan tema warna yang berbeda-beda.

Contoh Kecil: Bayangkan Anda menggunakan warna biru #3498db di 20 tempat berbeda di CSS Anda. Jika ingin menggantinya, Anda harus mencari dan mengganti semua 20 instance tersebut. Dengan CSS Variables:

/* Definisikan variabel */
:root {
  --brand-color: #3498db;
}

/* Gunakan variabel */
.header { background-color: var(--brand-color); }
.button-primary { background-color: var(--brand-color); }
/* ...dan seterusnya */

Jika ingin mengganti warna brand, cukup ubah nilai --brand-color di :root.


2. Dasar CSS Variables

2.1. Sintaks dan Deklarasi

Variabel CSS dideklarasikan dengan dua tanda hubung di depannya (--) dan bersifat case-sensitive (membedakan huruf besar dan kecil).

Deklarasi di :root (Global Scope): Cara paling umum untuk mendeklarasikan variabel global adalah di dalam pseudo-class :root. Ini membuat variabel tersedia di seluruh dokumen HTML.

:root {
  --primary-color: #3498db; /* Warna biru */
  --secondary-color: #2ecc71; /* Warna hijau */
  --text-color-main: #333333;
  --font-main: 'Open Sans', sans-serif;
  --spacing-medium: 16px;
}

Penggunaan dengan var(): Untuk menggunakan variabel, Anda menggunakan fungsi var():

h1 {
  color: var(--primary-color);
  font-family: var(--font-main);
}

.container {
  padding: var(--spacing-medium);
}

2.2. Variabel Lokal (Local Scope)

Variabel juga bisa dideklarasikan di dalam selector tertentu, yang membuatnya menjadi variabel lokal dan hanya berlaku untuk selector tersebut dan turunannya (children). Variabel lokal akan menimpa variabel global dengan nama yang sama.

:root {
  --text-color: black;
}

.sidebar {
  --text-color: white; /* Variabel lokal untuk .sidebar */
  background-color: #333;
  color: var(--text-color); /* Akan menggunakan 'white' */
}

.main-content {
  color: var(--text-color); /* Akan menggunakan 'black' dari :root */
}

2.3. Fallback Value (Nilai Cadangan)

Fungsi var() bisa menerima argumen kedua sebagai nilai cadangan (fallback). Jika variabel yang dipanggil tidak terdefinisi, nilai cadangan ini akan digunakan.

.element {
  color: var(--undefined-color, #000000); /* Jika --undefined-color tidak ada, warna akan jadi hitam */
  background-color: var(--brand-background, var(--primary-color, blue)); /* Bisa juga fallback ke variabel lain */
}

3. Studi Kasus: Membuat Theme Switcher (Mode Terang & Gelap)

Sekarang mari kita terapkan pengetahuan kita untuk membuat fitur pengalih tema antara mode terang (light) dan mode gelap (dark).

3.1. Struktur HTML Sederhana

Buat file index.html dengan beberapa elemen dasar yang akan terpengaruh oleh perubahan tema, dan sebuah tombol untuk mengalihkannya.

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS Variables & Theme Switcher</title>
    <link rel="stylesheet" href="style.css">
    <!-- Font Awesome untuk ikon matahari/bulan (opsional) -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
</head>
<body> <!-- Kita akan menambahkan class 'dark-theme' di sini dengan JS -->

    <header class="site-header">
        <div class="container header-content">
            <h1 class="site-title">Website Keren Saya</h1>
            <button id="themeToggleButton" class="theme-toggle-button" aria-label="Alihkan Tema">
                <i class="fas fa-sun icon-sun"></i>
                <i class="fas fa-moon icon-moon" style="display: none;"></i>
            </button>
        </div>
    </header>

    <main class="container site-content">
        <article class="card">
            <h2>Judul Artikel</h2>
            <p>Ini adalah paragraf contoh. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            <a href="#" class="card-link">Baca Selengkapnya</a>
        </article>

        <article class="card">
            <h2>Artikel Lain</h2>
            <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
            <a href="#" class="card-link">Baca Selengkapnya</a>
        </article>

        <button class="action-button">Tombol Aksi</button>
    </main>

    <footer class="site-footer-main">
        <div class="container">
            <p>&copy; <span id="currentYear"></span> Nama Anda. Tema dengan CSS Variables.</p>
        </div>
    </footer>

    <script src="script.js"></script>
</body>
</html>

Catatan HTML:

  • Tombol themeToggleButton memiliki dua ikon (matahari untuk mode terang, bulan untuk mode gelap) yang akan kita toggle visibilitasnya dengan JavaScript.
  • Kita akan menambahkan kelas .dark-theme ke elemen <body> menggunakan JavaScript untuk mengaktifkan mode gelap.

3.2. CSS dengan Variabel Tema

Buat file style.css. Kita akan mendefinisikan variabel untuk mode terang (default) di :root dan kemudian menimpanya untuk mode gelap saat kelas .dark-theme ada di body.

/* style.css */
/* 1. Deklarasi Variabel Tema Default (Light Mode) di :root */
:root {
    --bg-color: #f0f4f8;         /* Latar belakang utama */
    --text-color: #333333;       /* Warna teks utama */
    --header-bg: #ffffff;        /* Latar belakang header */
    --header-text: #2c3e50;      /* Teks di header */
    --card-bg: #ffffff;          /* Latar belakang kartu */
    --card-border: #e0e0e0;      /* Border kartu */
    --link-color: #3498db;       /* Warna link */
    --button-bg: #3498db;        /* Latar tombol aksi */
    --button-text: #ffffff;      /* Teks tombol aksi */
    --footer-bg: #2c3e50;       /* Latar footer */
    --footer-text: #bdc3c7;     /* Teks footer */

    /* Transisi untuk perubahan tema yang mulus */
    --theme-transition-duration: 0.3s;
}

/* 2. Deklarasi Variabel untuk .dark-theme */
/* Saat body memiliki kelas .dark-theme, variabel ini akan digunakan */
body.dark-theme {
    --bg-color: #1e272e;
    --text-color: #ecf0f1;
    --header-bg: #2c3e50;
    --header-text: #ecf0f1;
    --card-bg: #2c3e50;
    --card-border: #4a6572;
    --link-color: #5dade2;       /* Biru lebih cerah di dark mode */
    --button-bg: #e67e22;        /* Oranye untuk aksen di dark mode */
    --button-text: #ffffff;
    --footer-bg: #1a2027;
    --footer-text: #7f8c8d;
}

/* Styling Dasar Global */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    line-height: 1.6;
    /* Terapkan variabel tema */
    background-color: var(--bg-color);
    color: var(--text-color);
    transition: background-color var(--theme-transition-duration) ease, 
                color var(--theme-transition-duration) ease;
}

3.3. CSS dengan Variabel Global

Sekarang, kita akan menggunakan variabel-variabel ini di seluruh stylesheet untuk menata elemen-elemen kita.

/* style.css (Lanjutan - Styling Elemen) */

.container {
    max-width: 960px;
    margin: 0 auto;
    padding: 0 20px;
}

/* Header */
.site-header {
    background-color: var(--header-bg);
    color: var(--header-text);
    padding: 20px 0;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    transition: background-color var(--theme-transition-duration) ease, 
                color var(--theme-transition-duration) ease;
}
.header-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.site-title {
    font-size: 1.8rem;
    margin: 0;
    color: var(--header-text); /* Atau bisa var(--link-color) jika ingin link */
}

/* Tombol Pengalih Tema */
.theme-toggle-button {
    background: none;
    border: 1px solid var(--text-color); /* Border mengikuti warna teks tema */
    color: var(--text-color); /* Ikon mengikuti warna teks tema */
    padding: 8px 12px;
    border-radius: 5px;
    cursor: pointer;
    font-size: 1.2rem;
    transition: background-color var(--theme-transition-duration) ease, 
                color var(--theme-transition-duration) ease,
                border-color var(--theme-transition-duration) ease;
}
.theme-toggle-button:hover {
    background-color: var(--text-color);
    color: var(--bg-color); /* Warna ikon terbalik saat hover */
}
.theme-toggle-button .fas { /* Styling ikon di dalam tombol */
    vertical-align: middle;
}

/* Konten Utama */
.site-content {
    padding: 30px 0;
}

.card {
    background-color: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: 8px;
    padding: 20px;
    margin-bottom: 20px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
    transition: background-color var(--theme-transition-duration) ease, 
                border-color var(--theme-transition-duration) ease;
}
.card h2 {
    color: var(--text-color); /* Teks di dalam kartu juga menggunakan variabel */
    margin-top: 0;
    margin-bottom: 10px;
}
.card p {
    color: var(--text-color);
    margin-bottom: 15px;
}
.card-link {
    color: var(--link-color);
    text-decoration: none;
    font-weight: bold;
}
.card-link:hover {
    text-decoration: underline;
}

/* Tombol Aksi */
.action-button {
    display: inline-block;
    background-color: var(--button-bg);
    color: var(--button-text);
    padding: 12px 25px;
    border: none;
    border-radius: 5px;
    text-decoration: none;
    font-size: 1rem;
    font-weight: bold;
    cursor: pointer;
    transition: background-color var(--theme-transition-duration) ease;
}
.action-button:hover {
    opacity: 0.9; /* Efek hover sederhana */
}

/* Footer */
.site-footer-main {
    background-color: var(--footer-bg);
    color: var(--footer-text);
    padding: 30px 0;
    text-align: center;
    margin-top: auto; /* Mendorong footer ke bawah jika konten pendek */
    transition: background-color var(--theme-transition-duration) ease, 
                color var(--theme-transition-duration) ease;
}

Penjelasan Styling dengan Variabel:

  • Setiap properti yang berkaitan dengan warna atau spasi yang mungkin berubah antar tema (seperti background-color, color, border-color) sekarang menggunakan fungsi var(--nama-variabel).
  • Perhatikan penambahan transition pada banyak elemen. Ini akan membuat perubahan warna dan latar belakang terlihat lebih mulus saat tema dialihkan.

Jika Anda membuka index.html sekarang, Anda akan melihat tampilan default (mode terang). Tombol pengalih tema belum berfungsi.


4. Menambahkan Interaktivitas dengan JavaScript

JavaScript akan digunakan untuk:

  1. Meng-toggle kelas .dark-theme pada elemen <body> saat tombol diklik.
  2. (Opsional tapi sangat direkomendasikan) Menyimpan preferensi tema pengguna di localStorage agar pilihan tema diingat saat mereka kembali ke situs.

Buat file script.js:

// script.js
document.addEventListener('DOMContentLoaded', () => {
    const themeToggleButton = document.getElementById('themeToggleButton');
    const bodyElement = document.body;
    const iconSun = themeToggleButton.querySelector('.icon-sun');
    const iconMoon = themeToggleButton.querySelector('.icon-moon');
    
    // Fungsi untuk menerapkan tema dan menyimpan preferensi
    const applyTheme = (theme) => {
        bodyElement.classList.remove('light-theme', 'dark-theme'); // Hapus tema sebelumnya
        bodyElement.classList.add(theme + '-theme'); // Tambahkan kelas tema baru (misal 'dark-theme')

        if (theme === 'dark') {
            iconSun.style.display = 'none';
            iconMoon.style.display = 'inline';
            themeToggleButton.setAttribute('aria-label', 'Alihkan ke Mode Terang');
        } else {
            iconSun.style.display = 'inline';
            iconMoon.style.display = 'none';
            themeToggleButton.setAttribute('aria-label', 'Alihkan ke Mode Gelap');
        }
        localStorage.setItem('theme', theme); // Simpan preferensi tema
    };

    // Cek tema yang tersimpan di localStorage atau preferensi sistem saat halaman dimuat
    let currentTheme = localStorage.getItem('theme');
    const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)').matches;

    if (!currentTheme) { // Jika tidak ada tema tersimpan di localStorage
        currentTheme = prefersDarkScheme ? 'dark' : 'light'; // Gunakan preferensi sistem
    }
    
    applyTheme(currentTheme); // Terapkan tema awal

    // Event listener untuk tombol pengalih tema
    themeToggleButton.addEventListener('click', () => {
        let newTheme = bodyElement.classList.contains('dark-theme') ? 'light' : 'dark';
        applyTheme(newTheme);
    });

    // (Opsional) Update ikon jika preferensi sistem berubah saat halaman terbuka
    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
        // Hanya update jika tidak ada tema yang dipilih manual oleh user di localStorage
        if (!localStorage.getItem('theme')) { 
            const newColorScheme = event.matches ? "dark" : "light";
            applyTheme(newColorScheme);
        }
    });

    // Update tahun di footer
    document.getElementById('currentYear').textContent = new Date().getFullYear();
});

Penjelasan JavaScript:

  1. Seleksi Elemen: Mengambil tombol, body, dan ikon.
  2. applyTheme(theme):
    • Menghapus kelas tema sebelumnya dari body (misalnya .light-theme atau .dark-theme).
    • Menambahkan kelas tema yang baru (theme + '-theme', misalnya dark-theme). Kita perlu memastikan CSS kita menggunakan .dark-theme (atau .light-theme jika diperlukan untuk override default). Untuk kasus ini, karena default adalah terang, kita hanya perlu .dark-theme. Jika default Anda berbeda, sesuaikan.
    • Mengganti ikon matahari/bulan.
    • Mengupdate aria-label pada tombol.
    • Menyimpan tema yang dipilih ke localStorage.setItem('theme', theme).
  3. Memuat Tema Awal:
    • Mengecek localStorage.getItem('theme') untuk melihat apakah pengguna sudah punya preferensi.
    • Jika tidak ada, ia mengecek window.matchMedia('(prefers-color-scheme: dark)').matches untuk mengetahui apakah sistem operasi pengguna disetel ke mode gelap.
    • Tema awal diterapkan menggunakan applyTheme().
  4. Event Listener Tombol:
    • Saat tombol diklik, ia menentukan tema baru (kebalikan dari tema saat ini) dan memanggil applyTheme().
  5. Listener Perubahan Preferensi Sistem (Opsional): Jika pengguna mengubah preferensi mode gelap/terang di level sistem operasi saat halaman sedang terbuka, dan mereka belum memilih tema secara manual di situs, tema situs akan ikut berubah.

Modifikasi CSS Sedikit untuk body: Karena kita menggunakan .dark-theme dan defaultnya adalah terang, kita bisa menganggap :root sebagai light-theme.

/* style.css (bagian :root dan body) */
:root {
    /* ... variabel untuk light mode ... */
}

/* Tidak perlu .light-theme secara eksplisit jika :root sudah light */

body.dark-theme {
    /* ... variabel untuk dark mode ... */
}

body {
    font-family: /* ... */;
    background-color: var(--bg-color);
    color: var(--text-color);
    transition: background-color var(--theme-transition-duration) ease, 
                color var(--theme-transition-duration) ease;
}

Pastikan nama kelas di JS (theme + '-theme') cocok dengan nama kelas di CSS (dark-theme). Jika Anda ingin juga kelas .light-theme untuk konsistensi, Anda bisa menambahkannya dan JS akan mengaturnya. Untuk contoh ini, default tanpa kelas tambahan sudah mewakili mode terang.


5. 📱 Responsive dan UX Tips

  • Animasi Transisi: Kita sudah menambahkan transition pada properti background-color dan color di banyak elemen (termasuk body, header, card, footer). Ini membuat pergantian tema menjadi mulus dan tidak instan.
    • Anda bisa juga menambahkan transisi pada border-color atau properti lain yang berubah.
    • Untuk transisi semua properti, Anda bisa menggunakan transition: all var(--theme-transition-duration) ease; pada selector global * atau pada elemen-elemen utama, tapi ini bisa kurang performan dibandingkan mentarget properti spesifik.
  • Ikon (🌞 / 🌚): Kita sudah menggunakan ikon dari Font Awesome. Pastikan ikon yang tepat ditampilkan sesuai tema.
  • Tema Mengikuti Preferensi Sistem (prefers-color-scheme) sebagai Default: JavaScript kita sudah melakukan ini. Jika tidak ada preferensi di localStorage, tema awal akan mengikuti pengaturan sistem operasi pengguna. Ini adalah UX yang baik.

6. 🧪 Pengujian dan Debugging

  • Cek di Browser Modern: Uji theme switcher Anda di Chrome, Firefox, Edge, dan Safari (jika memungkinkan). CSS Variables didukung dengan baik di browser modern.
  • Cek Fallback Value (jika ada): Jika Anda menggunakan variabel yang mungkin tidak terdefinisi dan memberikan fallback, uji skenario tersebut.
  • Perilaku Tanpa JavaScript:
    • Secara default, tanpa JavaScript, situs akan tampil dalam mode terang (sesuai variabel di :root). Tombol pengalih tema tidak akan berfungsi. Ini adalah graceful degradation yang baik.
    • Jika Anda ingin defaultnya mengikuti preferensi sistem meskipun JavaScript mati (hanya dengan CSS), Anda bisa menggunakan media query prefers-color-scheme langsung di CSS untuk menimpa variabel di :root (lebih advance, dan mungkin sedikit berkonflik dengan pendekatan JS untuk localStorage).
      /* Contoh CSS-only dark mode berdasarkan preferensi sistem (tanpa JS) */
      /* :root { --bg-color: lightblue; --text-color: black; }
      @media (prefers-color-scheme: dark) {
          :root { --bg-color: darkblue; --text-color: white; }
      }
      body { background-color: var(--bg-color); color: var(--text-color); } */
      Namun, pendekatan JS yang kita gunakan (dengan localStorage) lebih fleksibel karena menyimpan pilihan pengguna secara eksplisit.
  • Gunakan DevTools:
    • Inspect elemen untuk melihat variabel CSS mana yang sedang diterapkan.
    • Di tab “Computed” (atau “Styles” lalu filter), Anda bisa melihat nilai akhir dari properti CSS dan dari variabel mana ia berasal.
    • Di tab “Application” -> “Local Storage”, Anda bisa melihat dan memanipulasi nilai theme yang disimpan.

7. Bonus: Tema Tambahan

Konsep CSS Variables dan pengalihan tema dengan kelas pada body sangat fleksibel. Anda bisa dengan mudah menambahkan tema lain:

Contoh: Tema Sepia

  1. CSS:
    /* style.css */
    body.sepia-theme {
        --bg-color: #f4e8c1;
        --text-color: #5b4636;
        --header-bg: #e9ddb0;
        --header-text: #5b4636;
        /* ... definisikan variabel lain untuk sepia ... */
        filter: sepia(0.6); /* Efek global sepia */
    }
    body.sepia-theme * { /* Pastikan transisi juga berlaku */
        transition: background-color var(--theme-transition-duration) ease, 
                    color var(--theme-transition-duration) ease,
                    border-color var(--theme-transition-duration) ease,
                    filter var(--theme-transition-duration) ease;
    }
  2. JavaScript: Anda perlu memodifikasi logika JS untuk menangani lebih dari dua tema (misalnya, tombol dropdown untuk memilih tema, atau siklus melalui beberapa tema).

Menggunakan data-theme Atribut: Alternatif untuk kelas pada body adalah menggunakan atribut data-theme:

<body data-theme="light">
/* style.css */
:root { /* atau [data-theme="light"] */
  /* Variabel light mode */
}

[data-theme="dark"] {
  /* Variabel dark mode */
}

[data-theme="sepia"] {
  /* Variabel sepia mode */
}

JavaScript Anda akan mengubah nilai document.body.dataset.theme. Ini bisa lebih rapi jika Anda memiliki banyak tema.


8. Penutup

Anda telah berhasil mempelajari dasar-dasar CSS Variables dan menggunakannya untuk membuat theme switcher yang fungsional! Ini adalah alat yang sangat kuat dalam toolkit CSS modern.

Ringkasan Manfaat CSS Variables:

  • Maintainable: Mengubah tema atau nilai desain global menjadi sangat mudah.
  • Scalable: Cocok untuk proyek kecil hingga besar, terutama dalam membangun design system yang konsisten.
  • Dinamis: Bisa diinteraksikan dengan JavaScript untuk fitur seperti mode terang/gelap atau kustomisasi tema oleh pengguna.
  • Mudah Dipahami: Sintaksnya intuitif (--nama-variabel dan var()).

CSS Variables membuka banyak kemungkinan untuk desain web yang lebih fleksibel dan dinamis. Jangan ragu untuk bereksperimen lebih lanjut dengan sistem tema Anda sendiri, menambahkan lebih banyak variabel, atau mencoba efek transisi yang berbeda.

Semoga tutorial ini bermanfaat dan menginspirasi Anda untuk terus menjelajahi kekuatan CSS!

Tutorial Terkait