Di Svelte, CSS sebuah komponen ditulis di tag <style> di file-nya sendiri, dan otomatis scoped: cuma mengenai elemen milik komponen itu. Bayangin papan menu kapur Warung Bu Sri. Bu Sri menghias papannya sendiri, dan coretannya gak pernah nyasar ke papan warung sebelah. Untuk menandai menu yang dipilih pembeli, dia menempel satu stiker "Pilihan" yang bisa dipindah dari menu ke menu. Kalau ada pengumuman untuk seluruh jalan, dia pasang spanduk yang dilihat semua orang. Di Svelte, papan itu <style> yang scoped, stiker yang pindah-pindah itu class:, dan spanduknya :global().
🧪 Tebakan cepat: di
<style>ada aturan.aktif { border-color: #c2410c; }, tapi markup-nya gak pernah menyebut kelasaktif. Kelasnya ditempel dari JavaScript biasa:kartu.classList.add("aktif"). Bingkai kartunya jadi oranye atau tetap abu-abu? Jawabannya ada di bagian "Selektor yang gak dipakai dibuang".
Style yang scoped, dari dekat
Ini App.svelte Warung Bu Sri. Dia memasang Sapaan dari pelajaran Props, lalu tiga kartu menu yang bisa dipilih:
<script>
import Sapaan from "./Sapaan.svelte"
let menu = ["Nasi Goreng", "Mie Ayam", "Es Teh"]
let dipilih = "Nasi Goreng"
</script>
<h1>Warung Bu Sri</h1>
<Sapaan nama="Sinta" />
{#each menu as nama (nama)}
<button class="kartu" class:aktif={dipilih === nama} on:click={() => (dipilih = nama)}>{nama}</button>
{/each}
<p>Pilihanmu: {dipilih}</p>
<style>
p { color: gray; }
.kartu { margin-right: 6px; padding: 6px 12px; border: 2px solid #d1d5db; border-radius: 8px; background: white; }
.aktif { border-color: #c2410c; background: #fff7ed; }
</style>
Svelte 4 mengubah style-nya jadi CSS ini (dipotong supaya pendek):
p.svelte-1l1nq9{color:gray}.kartu.svelte-1l1nq9{margin-right:6px;...}.aktif.svelte-1l1nq9{border-color:#c2410c;background:#fff7ed}
Dan DOM-nya jadi begini:
<h1>Warung Bu Sri</h1>
<p>Selamat datang, Sinta!</p>
<button class="kartu svelte-1l1nq9 aktif">Nasi Goreng</button>
<button class="kartu svelte-1l1nq9">Mie Ayam</button>
<button class="kartu svelte-1l1nq9">Es Teh</button>
<p class="svelte-1l1nq9">Pilihanmu: Nasi Goreng</p>
svelte-1l1nq9adalah kelas scope. Compiler menghitungnya dari isi<style>, jadi kelasnya berganti kalau CSS-nya diubah.- Tiap selektor dapat kelas itu sekali, dan tiap elemen App yang bisa cocok ikut dapat kelas itu.
- Paragraf Sapaan gak punya kelasnya, jadi tetap hitam walaupun App punya aturan
p.<h1>juga gak dapat, karena gak ada aturan untukh1.
class:aktif: kelas yang nyala-mati
class:aktif={kondisi} memasang kelas aktif saat kondisinya true dan melepasnya saat false. Kelas lain di elemen itu gak terganggu.
| Kejadian | dipilih |
Kartu Nasi Goreng | Kartu Mie Ayam |
|---|---|---|---|
| Awal | "Nasi Goreng" |
kartu svelte-1l1nq9 aktif |
kartu svelte-1l1nq9 |
| Klik Mie Ayam | "Mie Ayam" |
kartu svelte-1l1nq9 |
kartu svelte-1l1nq9 aktif |
class="kartu"tetap terpasang.class:aktifcuma menambah atau melepasaktif.- Bentuk singkat: kalau nama variabelnya sama dengan nama kelasnya,
class:aktif={aktif}cukup ditulisclass:aktif. Latihan pelajaran ini memakai bentuk itu:let active = truelalu<p class:active>. - Satu elemen boleh punya beberapa:
class:aktif={dipilih === nama} class:habis={stok === 0}. - Menulis string,
class="kartu {dipilih === nama ? 'aktif' : ''}", juga jalan.class:lebih pendek dan lebih jelas maksudnya.
Selektor yang gak dipakai dibuang
Compiler cuma membaca markup komponen itu. Selektor yang gak mungkin cocok dengan elemen mana pun dibuang dari CSS, dan compiler memberi warning:
Unused CSS selector ".aktif"
- Hapus
class:aktifdari kartu, dan gak ada elemen di markup yang bisa punya kelasaktif. Aturan.aktifhilang dari CSS hasil compile. - Kelas yang ditempel lewat
kartu.classList.add("aktif")gak punya aturan untuk dipakai, jadi bingkainya tetap abu-abu. Itu jawaban tebakannya. Pasang kelasnya di markup, lewatclass:aktif. - Warning yang sama menangkap salah ketik:
.aktivdi style, padahal markup-nya menulisaktif.
:global(): sengaja keluar dari scope
Kadang sebuah aturan memang harus berlaku di luar komponen: untuk body, atau untuk isi {@html} yang gak dapat kelas scope. Bungkus selektornya dengan :global(...):
<style>
:global(body) { margin: 0; }
:global(p) { color: gray; }
.deskripsi :global(strong) { color: #c2410c; }
</style>
:global(body)dicetak jadibody{margin:0}tanpa kelas, jadi berlaku di seluruh halaman.:global(p)di App dicetakp{color:gray}. Paragraf Sapaan ikut abu-abu, begitu juga semua<p>lain di aplikasi..deskripsi :global(strong): bagian.deskripsitetap scoped, cumastrongdi dalamnya yang bebas. Ini cara paling aman untuk merapikan isi{@html}.
style: untuk satu properti
style:properti={nilai} mengisi satu properti CSS inline dari JavaScript:
<script>
let ukuran = 24
let tutup = false
</script>
<h1 style:font-size="{ukuran}px" style:color={tutup ? "gray" : null}>Warung Bu Sri</h1>
- Hasilnya
<h1 style="font-size: 24px;">. Ubahukuranjadi 28, dan judulnya ikut membesar. - Nilai
nullatauundefinedmenghapus properti itu, jadicolorbaru muncul saattutupbernilaitrue. - Pakai
style:untuk nilai yang berubah dari data. Tampilan yang tetap tulis di<style>.
Latihan: paragraf biru
Kode awalnya <p>Teks berwarna biru</p>. Jawabannya:
<script>
let active = true
</script>
<p class:active>Teks berwarna biru</p>
<style>
p { color: gray; }
.active { color: blue; }
</style>
Svelte 4 mencetak p.svelte-150wy2m{color:gray}.active.svelte-150wy2m{color:blue}, dan paragrafnya jadi <p class="svelte-150wy2m active">.
- Kedua aturan cocok dengan paragraf itu. Yang menang yang lebih spesifik:
.active.svelte-150wy2mpunya dua kelas,p.svelte-150wy2mcuma satu kelas dan satu elemen. Jadi warnanya biru,rgb(0, 0, 255), di urutan mana pun aturannya ditulis. - Penguji mencari
class:dan<style>di kodemu, lalu membaca warna paragrafnya.
Svelte 5
<style> yang scoped, class:, style:, dan :global() ditulis sama persis di Svelte 5. Sejak Svelte 5.16, atribut class juga menerima objek: class={{ kartu: true, aktif: dipilih === nama }} artinya sama dengan class="kartu" class:aktif={dipilih === nama}.
⚠️ Jebakan yang sering ketemu
- Kelas yang ditempel dari luar markup.
classList.add("aktif")gak kena style scoped, karena compiler sudah membuang.aktifdengan warningUnused CSS selector. Pakaiclass:aktifdi markup. :global()yang terlalu lebar.:global(p)mengenai semua paragraf di aplikasi, termasuk milik komponen lain. Batasi lewat induknya:.deskripsi :global(p).- Mengira urutan yang menentukan.
.activetetap mengalahkanpwalaupun ditulis duluan, karena lebih spesifik. - Biru tanpa
class:dan<style>. Paragraf yang dibirukan lewat atributstyle="color: blue"saja gak lolos latihannya. Penguji mencari keduanya di kodemu.
TL;DR: CSS di <style> komponen otomatis scoped: compiler menambah kelas seperti svelte-1l1nq9 ke tiap selektor dan ke elemen milik komponen itu, jadi style gak bocor ke komponen lain. class:aktif={kondisi} memasang kelas aktif saat kondisinya true dan melepasnya saat false; kalau nama variabelnya sama, cukup class:aktif. Selektor yang gak cocok dengan markup dibuang dengan warning Unused CSS selector, jadi kelas yang ditempel lewat JavaScript gak kena style. :global(selector) sengaja keluar dari scope, misalnya :global(body). style:font-size="{ukuran}px" mengisi satu properti dari data, dan null menghapusnya. Svelte 5 menulis semuanya sama. Latihannya: let active = true, <p class:active>Teks berwarna biru</p>, dan <style> dengan p { color: gray; } lalu .active { color: blue; }, sehingga paragrafnya biru.