Untuk apa CSS :scope pseudo-class?

:scope ditentukan dalam Pemilih CSS 4 sebagai:

Pseudo-class yang mewakili elemen apa pun yang ada dalam kumpulan elemen referensi kontekstual. Ini adalah kumpulan elemen (yang berpotensi kosong) yang ditentukan secara eksplisit, seperti yang ditentukan oleh querySelector(), atau elemen induk dari elemen <style scoped>, yang digunakan untuk "menentukan cakupan" selektor sehingga hanya cocok dalam sub-pohon.

Contoh penggunaannya ada 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 dalam ul pertama menjadi merah dan, karena aturan :scope, akan menempatkan batas di sekitar ul. Hal ini karena dalam konteks <style scoped> ini, ul cocok dengan :scope. Ini 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 mengetahui querySelector() dan querySelectorAll() versi Element. Daripada membuat kueri untuk seluruh dokumen, Anda dapat membatasi set hasil 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, dalam contoh kedua, browser menemukan semua elemen a, lalu memfilter elemen yang tidak ada dalam elemen scope. Cara ini berfungsi, tetapi dapat menyebabkan beberapa perilaku aneh jika Anda tidak berhati-hati. Baca selanjutnya.

Saat querySelector salah

Ada aspek yang sangat penting dalam spesifikasi Pemilih yang sering diabaikan orang. Meskipun querySelector[All]() dipanggil pada elemen, pemilih masih dievaluasi dalam konteks seluruh dokumen. Artinya, hal-hal yang tidak terduga dapat terjadi:

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

Apa-apaan ini? Dalam contoh pertama, ul adalah elemen saya, tetapi saya masih dapat menggunakannya dan mencocokkan node. Di bagian kedua, body bahkan bukan turunan dari elemen saya, tetapi "body ul a" masih cocok. Kedua hal ini membingungkan dan tidak seperti yang Anda harapkan.

Sebaiknya buat perbandingan dengan jQuery di sini, yang menggunakan pendekatan yang tepat dan melakukan hal yang Anda harapkan:

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

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

Memperbaiki querySelector dengan :scope

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

Anda dapat menggunakannya untuk membatasi pemilih ke elemen konteks. Mari kita lihat contohnya. Berikut ini, :scope digunakan untuk "mencakup" pemilih ke sub-pohon elemen cakupan. Benar, saya 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

Penggunaan :scope membuat semantik metode querySelector() sedikit lebih dapat diprediksi dan selaras dengan yang sudah dilakukan oleh jQuery dan lainnya.

Meningkatkan performa?

Belum :(

Saya ingin tahu apakah penggunaan :scope di qS/qSA akan meningkatkan performa. Jadi… seperti engineer yang baik, saya membuat pengujian. Alasan saya: area permukaan yang lebih kecil bagi browser untuk melakukan pencocokan pemilih berarti pencarian lebih cepat.

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