Salah satu fitur preprosesor CSS favorit kami kini sudah ada di dalam bahasa: aturan gaya bertingkat.
Sebelum bertingkat, setiap pemilih harus dideklarasikan secara eksplisit, terpisah satu sama lain. Hal ini menyebabkan pengulangan, stylesheet yang besar, dan pengalaman penulisan yang tersebar.
.nesting { color: hotpink; } .nesting > .is { color: rebeccapurple; } .nesting > .is > .awesome { color: deeppink; }
Setelah bertingkat, pemilih dapat di lanjutkan dan aturan gaya terkait dapat dikelompokkan di dalamnya.
.nesting { color: hotpink; > .is { color: rebeccapurple; > .awesome { color: deeppink; } } }
Fitur bertingkat membantu developer dengan mengurangi kebutuhan untuk mengulang pemilih sekaligus menempatkan aturan gaya untuk elemen terkait. Fitur ini juga dapat membantu gaya cocok dengan HTML yang ditargetkan. Jika komponen .nesting dalam contoh sebelumnya dihapus dari project, Anda dapat menghapus seluruh grup, bukan menelusuri file untuk instance pemilih terkait.
Fitur bertingkat dapat membantu: - Pengorganisasian - Mengurangi ukuran file - Refactoring
Fitur bertingkat tersedia mulai dari Chrome 112 dan juga tersedia untuk dicoba di Safari Technical Preview 162.
Mulai menggunakan CSS Nesting
Di seluruh bagian postingan ini,sandbox demo berikut digunakan untuk membantu Anda memvisualisasikan pilihan. Dalam status default ini, tidak ada yang dipilih dan semuanya terlihat. Dengan memilih berbagai bentuk dan ukuran, Anda dapat mempraktikkan sintaksis dan melihatnya beraksi.

Di dalam sandbox terdapat lingkaran, segitiga, dan persegi. Beberapa berukuran kecil, sedang, atau besar. Yang lain berwarna biru, merah muda, atau ungu. Semuanya berada di dalam elemen penampung .demo. Berikut adalah pratinjau elemen HTML yang akan Anda targetkan.
<div class="demo">
<div class="sm triangle pink"></div>
<div class="sm triangle blue"></div>
<div class="square blue"></div>
<div class="sm square pink"></div>
<div class="sm square blue"></div>
<div class="circle pink"></div>
…
</div>
Contoh bertingkat
CSS nesting memungkinkan Anda menentukan gaya untuk elemen dalam konteks pemilih lain.
.parent {
color: blue;
.child {
color: red;
}
}
Dalam contoh ini, pemilih .child class bertingkat dalam
pemilih .parent class. Artinya, pemilih .child bertingkat hanya akan berlaku untuk elemen yang merupakan turunan dari elemen dengan class .parent.
Contoh ini dapat ditulis secara alternatif menggunakan simbol &, untuk menandakan secara eksplisit tempat class induk harus ditempatkan.
.parent {
color: blue;
& .child {
color: red;
}
}
Kedua contoh ini secara fungsional setara dan alasan Anda memiliki opsi akan menjadi lebih jelas saat contoh yang lebih canggih dieksplorasi dalam artikel ini.
Memilih lingkaran
Untuk contoh pertama ini, tugasnya adalah menambahkan gaya untuk memudarkan dan mengaburkan lingkaran di dalam demo.
Tanpa bertingkat, CSS saat ini:
.demo .circle {
opacity: .25;
filter: blur(25px);
}
Dengan bertingkat, ada dua cara yang valid:
/* & is explicitly placed in front of .circle */
.demo {
& .circle {
opacity: .25;
filter: blur(25px);
}
}
atau
/* & + " " space is added for you */
.demo {
.circle {
opacity: .25;
filter: blur(25px);
}
}
Hasilnya, semua elemen di dalam .demo dengan class .circle akan
dikaburkan dan hampir tidak terlihat:
Memilih segitiga dan persegi
Tugas ini mengharuskan pemilihan beberapa elemen bertingkat, yang juga disebut pemilih grup.
Tanpa bertingkat, CSS saat ini, ada dua cara:
.demo .triangle,
.demo .square {
opacity: .25;
filter: blur(25px);
}
atau, menggunakan :is()
/* grouped with :is() */
.demo :is(.triangle, .square) {
opacity: .25;
filter: blur(25px);
}
Dengan bertingkat, berikut dua cara yang valid:
.demo {
& .triangle,
& .square {
opacity: .25;
filter: blur(25px);
}
}
atau
.demo {
.triangle, .square {
opacity: .25;
filter: blur(25px);
}
}
Hasilnya, hanya elemen .circle yang tetap berada di dalam .demo:
Memilih segitiga dan lingkaran besar
Tugas ini memerlukan pemilih gabungan, dengan elemen harus memiliki kedua class agar dapat dipilih.
Tanpa bertingkat, CSS saat ini:
.demo .lg.triangle,
.demo .lg.square {
opacity: .25;
filter: blur(25px);
}
atau
.demo .lg:is(.triangle, .circle) {
opacity: .25;
filter: blur(25px);
}
Dengan bertingkat, berikut dua cara yang valid:
.demo {
.lg.triangle,
.lg.circle {
opacity: .25;
filter: blur(25px);
}
}
atau
.demo {
.lg {
&.triangle,
&.circle {
opacity: .25;
filter: blur(25px);
}
}
}
Hasilnya, semua segitiga dan lingkaran besar disembunyikan di dalam .demo:
Tips profesional dengan pemilih gabungan dan bertingkat
Simbol & adalah teman Anda di sini karena simbol ini menunjukkan secara eksplisit cara menggabungkan pemilih bertingkat. Perhatikan contoh berikut:
.demo {
.lg {
.triangle,
.circle {
opacity: .25;
filter: blur(25px);
}
}
}
Meskipun merupakan cara yang valid untuk bertingkat, hasilnya tidak akan cocok dengan elemen yang mungkin Anda harapkan.
Alasannya adalah tanpa & untuk menentukan hasil yang diinginkan dari .lg.triangle,
.lg.circle yang digabungkan, hasil sebenarnya adalah .lg .triangle, .lg
.circle; pemilih turunan.
Memilih semua bentuk kecuali yang berwarna merah muda
Tugas ini memerlukan class semu fungsional negasi, dengan elemen tidak boleh memiliki pemilih yang ditentukan.
Tanpa bertingkat, CSS saat ini:
.demo :not(.pink) {
opacity: .25;
filter: blur(25px);
}
Dengan bertingkat, berikut dua cara yang valid:
.demo {
:not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
atau
.demo {
& :not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
Hasilnya, semua bentuk yang tidak berwarna merah muda disembunyikan di dalam .demo:
Presisi dan fleksibilitas dengan &
Katakanlah Anda ingin menargetkan .demo dengan pemilih :not(). & diperlukan untuk itu:
.demo {
&:not() {
...
}
}
Hal ini menggabungkan .demo dan :not() menjadi .demo:not(), berbeda dengan contoh sebelumnya
yang memerlukan .demo :not(). Pengingat ini menjadi sangat penting saat ingin menyematkan interaksi :hover.
.demo {
&:hover {
/* .demo:hover */
}
:hover {
/* .demo :hover */
}
}
Contoh bertingkat lainnya
Spesifikasi CSS untuk bertingkat dilengkapi dengan lebih banyak contoh. Jika Anda ingin mempelajari sintaksis lebih lanjut melalui contoh, spesifikasi ini mencakup berbagai contoh yang valid dan tidak valid.
Beberapa contoh berikutnya akan memperkenalkan fitur bertingkat CSS secara singkat, untuk membantu Anda memahami luasnya kemampuan yang diperkenalkan.
Bertingkat @media
Sangat mengganggu jika harus berpindah ke area stylesheet lain untuk menemukan kondisi kueri media yang mengubah pemilih dan gayanya. Gangguan tersebut tidak ada lagi dengan kemampuan untuk menyematkan kondisi tepat di dalam konteks.
Untuk kemudahan sintaksis, jika kueri media bertingkat hanya mengubah gaya untuk konteks pemilih saat ini, sintaksis minimal dapat digunakan.
.card {
font-size: 1rem;
@media (width >= 1024px) {
font-size: 1.25rem;
}
}
Penggunaan & secara eksplisit juga dapat digunakan:
.card {
font-size: 1rem;
@media (width >= 1024px) {
&.large {
font-size: 1.25rem;
}
}
}
Contoh ini menunjukkan sintaksis yang diperluas dengan &, sekaligus menargetkan kartu .large untuk menunjukkan bahwa fitur bertingkat tambahan terus berfungsi.
Pelajari lebih lanjut aturan @bertingkat.
Bertingkat di mana saja
Semua contoh hingga saat ini telah dilanjutkan atau ditambahkan ke konteks sebelumnya. Anda dapat sepenuhnya mengubah atau mengatur ulang konteks jika diperlukan.
.card {
.featured & {
/* .featured .card */
}
}
Simbol & mewakili referensi ke objek pemilih (bukan string) dan dapat ditempatkan di mana saja dalam pemilih bertingkat. Simbol ini bahkan dapat ditempatkan beberapa kali:
.card {
.featured & & & {
/* .featured .card .card .card */
}
}
Meskipun contoh ini terlihat agak tidak berguna, ada skenario tertentu yang memungkinkan pengulangan konteks pemilih menjadi berguna.
Contoh bertingkat yang tidak valid
Ada beberapa skenario sintaksis bertingkat yang tidak valid dan mungkin mengejutkan Anda jika Anda telah bertingkat di preprosesor.
Bertingkat dan penggabungan
Banyak konvensi penamaan class CSS mengandalkan kemampuan bertingkat untuk menggabungkan atau menambahkan pemilih seolah-olah pemilih tersebut adalah string. Hal ini tidak berfungsi dalam CSS bertingkat karena pemilih bukan string, melainkan referensi objek.
.card {
&--header {
/* is not equal to ".card--header" */
}
}
Penjelasan yang lebih mendalam dapat ditemukan dalam spesifikasi.
Contoh bertingkat yang rumit
Bertingkat dalam daftar pemilih dan :is()
Perhatikan blok CSS bertingkat berikut:
.one, #two {
.three {
/* some styles */
}
}
Ini adalah contoh pertama yang dimulai dengan daftar pemilih, lalu terus bertingkat lebih lanjut. Contoh sebelumnya hanya diakhiri dengan daftar pemilih. Tidak ada yang tidak valid dalam contoh bertingkat ini, tetapi ada detail implementasi yang berpotensi rumit tentang bertingkat di dalam daftar pemilih, terutama yang menyertakan pemilih ID.
Agar intent bertingkat berfungsi, daftar pemilih yang bukan bertingkat paling dalam akan digabungkan dengan :is() oleh browser. Penggabungan ini mempertahankan pengelompokan daftar pemilih dalam konteks yang ditulis. Efek samping dari pengelompokan ini, :is(.one, #two), adalah bahwa pengelompokan ini mengadopsi spesifisitas skor tertinggi dalam pemilih di dalam tanda kurung. Cara kerja :is() selalu seperti ini, tetapi mungkin mengejutkan saat menggunakan sintaksis bertingkat karena tidak sama persis dengan yang ditulis. Ringkasan trik; bertingkat dengan ID dan daftar pemilih dapat menghasilkan pemilih spesifisitas yang sangat tinggi.
Untuk meringkas contoh yang rumit dengan jelas, blok bertingkat sebelumnya akan diterapkan ke dokumen sebagai berikut:
:is(.one, #two) .three {
/* some styles */
}
Perhatikan atau ajari linter Anda untuk memperingatkan saat bertingkat di dalam daftar pemilih yang menggunakan pemilih ID, spesifisitas semua bertingkat dalam daftar pemilih tersebut akan tinggi.
Mencampur bertingkat dan deklarasi
Perhatikan blok CSS bertingkat berikut:
.card {
color: green;
& { color: blue; }
color: red;
}
Warna elemen .card akan menjadi blue.
Deklarasi gaya yang bercampur akan diangkat ke bagian atas, seolah-olah ditulis sebelum bertingkat. Detail selengkapnya dapat ditemukan dalam spesifikasi.
Ada cara untuk mengatasinya. Berikut ini menggabungkan tiga gaya warna dalam &, yang mempertahankan urutan kaskade seperti yang mungkin dimaksudkan oleh penulis. Warna elemen .card akan menjadi merah.
.card {
color: green;
& { color: blue; }
& { color: red; }
}
Sebenarnya, sebaiknya gabungkan gaya apa pun yang mengikuti bertingkat dengan &.
.card {
color: green;
@media (prefers-color-scheme: dark) {
color: lightgreen;
}
& {
aspect-ratio: 4/3;
}
}
Deteksi fitur
Ada dua cara yang bagus untuk mendeteksi fitur CSS bertingkat: gunakan bertingkat atau gunakan @supports untuk memeriksa kemampuan penguraian pemilih bertingkat.

Menggunakan bertingkat:
html {
.has-nesting {
display: block;
}
.no-nesting {
display: none;
}
}
Menggunakan @supports:
@supports (selector(&)) {
/* nesting parsing available */
}
Kolega saya, Bramus, memiliki Codepen yang bagus yang menunjukkan strategi ini.
Melakukan proses debug dengan Chrome DevTools
Dukungan saat ini di DevTools untuk bertingkat sangat minim. Saat ini, Anda akan menemukan gaya yang ditampilkan di panel Styles seperti yang diharapkan, tetapi pelacakan bertingkat dan konteks pemilih lengkapnya belum didukung. Kami memiliki desain dan rencana untuk membuat hal ini transparan dan jelas.

Chrome 113 berencana untuk memiliki dukungan tambahan untuk CSS bertingkat. Terus ikuti perkembangannya.
Masa depan
CSS Nesting hanya ada di versi 1. Versi 2 akan memperkenalkan lebih banyak gula sintaksis dan berpotensi lebih sedikit aturan untuk diingat. Ada banyak permintaan agar penguraian bertingkat tidak dibatasi atau memiliki momen yang rumit.
Fitur bertingkat adalah peningkatan besar pada bahasa CSS. Fitur ini memiliki implikasi penulisan pada hampir setiap aspek arsitektur CSS. Dampak besar ini perlu dieksplorasi dan dipahami secara mendalam sebelum versi 2 dapat ditentukan secara efektif.
Sebagai pemikiran terakhir, berikut adalah demo
yang menggunakan @scope, bertingkat, dan @layer secara bersamaan. Semuanya sangat menarik.
