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>© <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 fungsivar(--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:
- Meng-toggle kelas
.dark-theme
pada elemen<body>
saat tombol diklik. - (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:
- Seleksi Elemen: Mengambil tombol, body, dan ikon.
applyTheme(theme)
:- Menghapus kelas tema sebelumnya dari
body
(misalnya.light-theme
atau.dark-theme
). - Menambahkan kelas tema yang baru (
theme + '-theme'
, misalnyadark-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)
.
- Menghapus kelas tema sebelumnya dari
- 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()
.
- Mengecek
- Event Listener Tombol:
- Saat tombol diklik, ia menentukan tema baru (kebalikan dari tema saat ini) dan memanggil
applyTheme()
.
- Saat tombol diklik, ia menentukan tema baru (kebalikan dari tema saat ini) dan memanggil
- 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 propertibackground-color
dancolor
di banyak elemen (termasukbody
,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.
- Anda bisa juga menambahkan transisi pada
- 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 dilocalStorage
, 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 untuklocalStorage
).
Namun, pendekatan JS yang kita gunakan (dengan/* 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); } */
localStorage
) lebih fleksibel karena menyimpan pilihan pengguna secara eksplisit.
- Secara default, tanpa JavaScript, situs akan tampil dalam mode terang (sesuai variabel di
- 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
- 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; }
- 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
danvar()
).
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!