Penyebaran CSS

Salah satu fitur praprosesor CSS favorit kami kini telah ditanamkan ke dalam bahasa: aturan gaya bertingkat.

Adam Argyle
Adam Argyle

Sebelum dibuat bertingkat, setiap pemilih harus dideklarasikan secara eksplisit, secara terpisah satu sama lain. Hal ini menyebabkan pengulangan, bulksheet dalam jumlah besar, dan pengalaman penulisan yang tersebar.

Sebelum
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

Setelah bertingkat, pemilih dapat dilanjutkan dan aturan gaya yang terkait dapat dikelompokkan di dalamnya.

Setelah
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

Coba ini di browser.

Penyusunan bertingkat membantu developer mengurangi kebutuhan untuk mengulangi pemilih sekaligus menemukan aturan gaya bersama untuk elemen terkait. Hal ini juga dapat membantu gaya agar 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.

Nesting dapat membantu: - Organisasi - Mengurangi ukuran file - Pemfaktoran ulang

Nesting tersedia mulai Chrome 112 dan juga tersedia untuk dicoba di Safari Technical Preview 162.

Memulai CSS Nesting

Sepanjang postingan ini,sandbox demo berikut digunakan untuk membantu Anda memvisualisasikan pilihan. Dalam status default ini, tidak ada yang dipilih dan semuanya akan terlihat. Dengan memilih berbagai bentuk dan ukuran, Anda dapat berlatih sintaksis dan melihat cara kerjanya.

Kotak, segitiga, dan persegi panjang berwarna-warni.

Di dalam sandbox terdapat lingkaran, segitiga, dan persegi. Ada yang kecil, sedang, atau besar. Lainnya berwarna biru, merah muda, atau ungu. Semuanya berada di dalam elemen yang berisi .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 tingkatan

Penyusunan bertingkat CSS memungkinkan Anda menentukan gaya untuk sebuah elemen dalam konteks pemilih lain.

.parent {
  color: blue;

  .child {
    color: red;
  }
}

Dalam contoh ini, pemilih class .child disusun bertingkat dalam pemilih class .parent. Artinya, pemilih .child bertingkat hanya akan diterapkan pada elemen yang merupakan turunan elemen dengan class .parent.

Contoh ini juga dapat ditulis menggunakan simbol &, untuk secara eksplisit menandakan tempat class induk harus ditempatkan.

.parent {
  color: blue;

  & .child {
    color: red;
  }
}

Kedua contoh ini setara secara fungsional dan alasan Anda memiliki opsi ini akan menjadi lebih jelas seiring dengan pembahasan contoh yang lebih lanjut dalam artikel ini.

Memilih lingkaran

Untuk contoh pertama, tugasnya adalah menambahkan gaya untuk memudar dan memburamkan hanya lingkaran di dalam demo.

Tanpa penyusunan bertingkat, CSS kini:

.demo .circle {
  opacity: .25;
  filter: blur(25px);
}

Dengan penyusunan 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 diburamkan dan hampir tidak terlihat:

Kisi-kisi bentuk warna-warni tidak lagi memiliki lingkaran,
    mereka sangat redup di latar belakang.
Coba demo

Memilih segitiga dan persegi

Tugas ini mengharuskan Anda memilih beberapa elemen bertingkat, juga disebut pemilih grup.

Tanpa penyusunan 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 penyusunan bertingkat, berikut ini 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:

Kisi bentuk warna-warni hanya menyisakan lingkaran,
    semua bentuk lainnya hampir tidak terlihat.
Coba demo

Memilih segitiga dan lingkaran besar

Tugas ini memerlukan pemilih gabungan, dengan elemen harus memiliki kedua class agar dapat dipilih.

Tanpa penyusunan bertingkat, CSS kini:

.demo .lg.triangle,
.demo .lg.square {
  opacity: .25;
  filter: blur(25px);
}

atau

.demo .lg:is(.triangle, .circle) {
  opacity: .25;
  filter: blur(25px);
}

Dengan penyusunan bertingkat, berikut ini 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:

{i>Grid<i} warna-warni hanya terlihat dalam bentuk kecil dan sedang.
Coba demo
Tips pro dengan pemilih gabungan dan nesting

Simbol & adalah teman Anda di sini karena 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 menyusun bertingkat, hasilnya tidak akan cocok dengan elemen yang mungkin Anda harapkan. Alasannya adalah bahwa 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 merah muda

Tugas ini memerlukan class pseudo fungsional negasi, dengan elemen tidak boleh memiliki pemilih yang ditentukan.

Tanpa penyusunan bertingkat, CSS kini:

.demo :not(.pink) {
  opacity: .25;
  filter: blur(25px);
}

Dengan penyusunan bertingkat, berikut ini 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:

Petak warna-warni kini bersifat monokrom, hanya menampilkan bentuk merah muda.
Coba demo
Presisi dan fleksibilitas dengan &

Misalnya Anda ingin menargetkan .demo dengan pemilih :not(). & diperlukan untuk hal berikut:

.demo {
  &:not() {
    ...
  }
}

Ini menggabungkan .demo dan :not() ke .demo:not(), berbeda dengan contoh sebelumnya yang memerlukan .demo :not(). Pengingat ini dibuat sangat penting saat ingin menyarangkan interaksi :hover.

.demo {
  &:hover {
    /* .demo:hover */
  }

  :hover {
    /* .demo :hover */
  }
}

Contoh tingkatan lainnya

Spesifikasi CSS untuk penyusunan bertingkat dikemas dengan lebih banyak contoh. Jika Anda ingin mempelajari lebih lanjut sintaksis melalui contoh, panduan ini mencakup berbagai contoh yang valid dan tidak valid.

Beberapa contoh berikutnya akan secara singkat memperkenalkan fitur penyusunan bertingkat CSS, untuk membantu Anda memahami cakupan kemampuan yang tersedia.

Menyusun @media

Berpindah ke area stylesheet yang lain dapat sangat mengganggu untuk menemukan kondisi kueri media yang mengubah pemilih dan gayanya. Gangguan tersebut hilang dengan kemampuan untuk menumpuk 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;
  }
}

Menggunakan & 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 fitur bertingkat tambahan yang terus berfungsi.

Pelajari @aturan bertingkat lebih lanjut.

Bersarang di mana saja

Semua contoh hingga tahap ini merupakan lanjutan 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. Kode ini bahkan dapat ditempatkan beberapa kali:

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

Meskipun contoh ini agak tidak berguna, tentu saja ada beberapa skenario ketika mampu mengulangi konteks pemilih akan sangat berguna.

Contoh tingkatan yang tidak valid

Ada beberapa skenario sintaksis bertingkat yang tidak valid dan mungkin mengejutkan Anda jika Anda telah menyarangkan praprosesor.

Nesting dan penyambungan

Banyak konvensi penamaan class CSS bergantung pada kemampuan penyusunan bertingkat untuk dapat menggabungkan atau menambahkan pemilih seolah-olah pemilih adalah string. Cara ini tidak berfungsi dalam penyusunan bertingkat CSS, karena pemilih bukan string, melainkan referensi objek.

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

Penjelasan yang lebih mendalam dapat ditemukan di spesifikasi.

Contoh penyusunan bertingkat yang rumit

Bertingkat dalam daftar pemilih dan :is()

Pertimbangkan blok CSS bertingkat berikut:

.one, #two {
  .three {
    /* some styles */
  }
}

Ini adalah contoh pertama yang dimulai dengan daftar pemilih dan kemudian terus disusun bertingkat lebih lanjut. Contoh sebelumnya hanya diakhiri dengan daftar pemilih. Tidak ada yang tidak valid dalam contoh tingkatan ini, tetapi ada detail implementasi yang berpotensi rumit tentang penyusunan bertingkat di dalam daftar pemilih, terutama yang menyertakan pemilih ID.

Agar intent tingkatan berfungsi, daftar pemilih yang bukan bagian dalam yang paling bertingkat, 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 kekhususan skor tertinggi dalam pemilih dalam tanda kurung. Begitulah cara kerja :is() selalu bekerja, tetapi mungkin mengejutkan saat menggunakan sintaksis bertingkat karena tidak sama persis dengan yang ditulis. Rangkuman triknya; bersarang dengan ID dan daftar pemilih dapat menghasilkan pemilih dengan kekhususan yang sangat tinggi.

Untuk meringkas contoh rumit dengan jelas, blok susunan sebelumnya akan diterapkan ke dokumen sebagai berikut:

:is(.one, #two) .three {
  /* some styles */
}

Awasi atau ajari linter untuk memperingatkan saat menyusun bertingkat dalam daftar pemilih yang menggunakan pemilih ID, kekhususan semua tingkatan dalam daftar pemilih tersebut akan tinggi.

Mengombinasikan nesting dan deklarasi

Pertimbangkan blok CSS bertingkat berikut:

.card {
  color: green;
  & { color: blue; }
  color: red;
}

Warna elemen .card akan menjadi blue.

Setiap deklarasi gaya campuran diangkat ke atas, seolah-olah ditulis sebelum terjadi tingkatan. Detail selengkapnya dapat ditemukan di spesifikasi.

Ada beberapa cara untuk mengatasinya. Kode berikut menggabungkan tiga gaya warna di &, yang mempertahankan urutan menurun seperti yang mungkin diinginkan penulis. Warna elemen .card akan berwarna merah.

.card {
  color: green;
  & { color: blue; }
  & { color: red; }
}

Bahkan, sebaiknya gabungkan gaya apa pun yang mengikuti pembuatan bertingkat dengan &.

.card {
  color: green;

  @media (prefers-color-scheme: dark) {
    color: lightgreen;
  }

  & {
    aspect-ratio: 4/3;
  }
}

Deteksi fitur

Ada dua cara yang efektif untuk mendeteksi penyusunan bertingkat CSS: menggunakan penyusunan bertingkat atau menggunakan @supports untuk memeriksa kemampuan penguraian pemilih bertingkat.

Screenshot demo Codepen Bramus, yang menanyakan apakah browser Anda mendukung
  penyusunan bertingkat CSS. Di bawah pertanyaan tersebut terdapat kotak hijau yang menandakan dukungan.

Menggunakan penyusunan 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.

Proses debug dengan Chrome DevTools

Dukungan saat ini di DevTools untuk penyarangan minimal. Saat ini, Anda akan menemukan gaya ditampilkan di panel Styles seperti yang diharapkan, tetapi pelacakan bertingkat dan konteks pemilih lengkapnya belum didukung. Kami memiliki desain dan rencana untuk membuatnya transparan dan jelas.

Screenshot sintaksis bertingkat di Chrome DevTools.

Chrome 113 berencana memiliki dukungan tambahan untuk penyusunan bertingkat CSS. Nantikan kabar terbaru.

Acara mendatang

Penyusunan CSS hanya pada versi 1. Versi 2 akan memperkenalkan lebih banyak sintaksis dan kemungkinan lebih sedikit aturan untuk dihafal. Ada banyak permintaan untuk penguraian bertingkat agar tidak dibatasi atau memiliki momen yang rumit.

Penyusunan (nesting) adalah peningkatan besar pada bahasa CSS. Ini memiliki implikasi penyusunan 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, penyusunan bertingkat, dan @layer secara bersamaan. Semuanya sangat mengasyikkan!

Kartu warna terang dengan latar belakang abu-abu. Kartu tersebut memiliki judul dan teks,
  beberapa tombol tindakan, dan gambar bergaya cyber punk.