Untuk apa CSS :scope pseudo-class?

:scope ditentukan di Pemilih CSS 4 sebagai:

Class-pseudo yang mewakili elemen apa pun yang berada dalam set elemen referensi kontekstual. Ini adalah set elemen (yang mungkin kosong) yang ditentukan secara eksplisit, seperti yang ditentukan oleh querySelector(), atau elemen induk dari elemen <style scoped>, yang digunakan untuk "mencakup" pemilih agar hanya cocok dalam sub-hierarki.

Contoh penggunaannya adalah dalam <style scoped> (info selengkapnya):

<style>
    li {
    color: blue;
    }
</style>

<ul>
    <style scoped>
    li {
        color: red;
    }
    :scope {
        border: 1px solid red;
    }
    </style>
    <li>abc</li>
    <li>def</li>
    <li>efg</li>
</ul>

<ul>
    <li>hij</li>
    <li>klm</li>
    <li>nop</li>
</ul>

Tindakan ini akan mewarnai elemen li di ul pertama menjadi merah dan, karena aturan :scope, menempatkan batas di sekitar ul. Hal ini karena dalam konteks <style scoped> ini, ul cocok dengan :scope. Itu adalah konteks lokal. Jika kita menambahkan aturan :scope di <style> luar, aturan tersebut akan cocok dengan seluruh dokumen. Pada dasarnya, setara dengan :root.

Elemen kontekstual

Anda mungkin sudah mengetahui versi Element dari querySelector() dan querySelectorAll(). Daripada membuat kueri seluruh dokumen, Anda dapat membatasi hasil yang disetel ke elemen kontekstual:

<ul>
    <li id="scope"><a>abc</a></li>
    <li>def</li>
    <li><a>efg</a></li>
</ul>
<script>
    document.querySelectorAll('ul a').length; // 2

    var scope = document.querySelector('#scope');
    scope.querySelectorAll('a').length; // 1
</script>

Saat dipanggil, browser akan menampilkan NodeList yang difilter untuk hanya menyertakan kumpulan node yang a.) cocok dengan pemilih dan b.) yang juga merupakan turunan dari elemen konteks. Jadi pada contoh kedua, browser menemukan semua elemen a, lalu memfilter yang tidak ada dalam elemen scope. Bisa, tapi bisa menyebabkan perilaku aneh jika Anda tidak berhati-hati. Baca selanjutnya.

Saat querySelector salah

Ada hal yang sangat penting dalam spesifikasi Pemilih yang sering diabaikan oleh orang-orang. Meskipun querySelector[All]() dipanggil pada elemen, pemilih tetap mengevaluasi dalam konteks keseluruhan dokumen. Ini berarti hal-hal yang tidak terduga dapat terjadi:

    scope.querySelectorAll('ul a').length); // 1
    scope.querySelectorAll('body ul a').length); // 1

Apa-apaan ini? Pada contoh pertama, ul adalah elemen saya, tetapi saya masih dapat menggunakannya dan mencocokkan node. Di contoh kedua, body bahkan bukan turunan dari elemen saya, tetapi "body ul a" tetap cocok. Keduanya membingungkan dan bukan yang Anda harapkan.

Ada baiknya membuat perbandingan dengan jQuery di sini, yang mengambil pendekatan yang tepat dan melakukan apa yang Anda harapkan:

    $(scope).find('ul a').length // 0
    $(scope).find('body ul a').length // 0

...masukkan :scope untuk mengatasi masalah semantik ini.

Memperbaiki querySelector dengan :scope

WebKit baru-baru ini mendapatkan dukungan untuk menggunakan kelas pseudo :scope di querySelector[All](). Anda dapat mengujinya di Chrome Canary 27.

Anda dapat menggunakannya untuk membatasi pemilih ke elemen konteks. Mari kita lihat contohnya. Dalam hal berikut, :scope digunakan untuk "mencakup" pemilih ke subhierarki elemen cakupan. Benar, aku mengatakan cakupan tiga kali!

    scope.querySelectorAll(':scope ul a').length); // 0
    scope.querySelectorAll(':scope body ul a').length); // 0
    scope.querySelectorAll(':scope a').length); // 1

Menggunakan :scope akan membuat semantik metode querySelector() sedikit lebih dapat diprediksi dan selaras dengan apa yang sudah dilakukan oleh metode lain seperti jQuery.

Performa menang?

Belum :(

Saya ingin tahu apakah penggunaan :scope di qS/qSA memberikan peningkatan performa. Jadi... seperti seorang engineer yang baik, saya melakukan pengujian. Alasan saya: jika area permukaan browser lebih sedikit untuk melakukan pencocokan pemilih, pencarian akan menjadi lebih cepat.

Dalam eksperimen saya, WebKit saat ini memerlukan waktu ~1,5-2x lebih lama daripada tidak menggunakan :scope. Drat! Saat crbug.com/222028 diperbaiki, menggunakannya secara teori akan memberi Anda sedikit peningkatan performa daripada tidak menggunakannya.