CSS :scope sözde sınıfının amacı nedir?

:scope, CSS Seçicileri 4'te şu şekilde tanımlanır:

Bağlamsal referans öğesi grubundaki tüm öğeleri temsil eden bir sözde sınıf. Bu, querySelector() tarafından belirtilen veya bir <style scoped> öğesinin üst öğesi gibi açıkça belirtilen bir (boş olabilecek) öğe grubudur. Bu grup, bir seçiciyi yalnızca bir alt ağaçta eşleşecek şekilde "kapsam"landırmak için kullanılır.

Bu özelliğin <style scoped> içinde kullanıldığı bir örnek (daha fazla bilgi):

<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>

Bu, ilk ul içindeki li öğelerini kırmızı renklendirir ve :scope kuralından dolayı ul öğesinin etrafına bir kenarlık ekler. Bunun nedeni, bu <style scoped> bağlamında ul'ın :scope ile eşleşmesidir. Yerel bağlamdır. Dış <style> içine bir :scope kuralı eklersek bu kural, belgenin tamamıyla eşleşir. Özetle, :root ile eşdeğerdir.

Bağlamsal öğeler

querySelector() ve querySelectorAll()'in Element sürümünü muhtemelen biliyorsunuzdur. Dokümanın tamamını sorgulamak yerine sonuç kümesini bağlamsal bir öğeyle kısıtlayabilirsiniz:

<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>

Bunlar çağrıldığında tarayıcı, yalnızca a.) seçiciyle eşleşen ve b.) aynı zamanda içerik öğesinin alt öğeleri olan düğüm kümesini içerecek şekilde filtrelenmiş bir NodeList döndürür. Dolayısıyla ikinci örnekte tarayıcı tüm a öğelerini bulur, ardından scope öğesinde olmayanları filtreler. Bu yöntem işe yarar ancak dikkatli olmazsanız bazı tuhaf davranışlara neden olabilir. Okumaya devam edin.

querySelector yanlış gittiğinde

Seçici spesifikasyonunda kullanıcıların sıklıkla gözden kaçırdığı gerçekten önemli bir nokta vardır. Bir öğede querySelector[All]() çağrıldığında bile seçiciler, belgenin tamamı bağlamında değerlendirilmeye devam eder. Bu durumda beklenmedik şeyler olabilir:

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

WTF! İlk örnekte ul öğem olsa da öğeyi kullanmaya ve düğümleri eşlemeye devam edebilirim. İkinci durumda, body öğemin alt öğesi bile değil ancak "body ul a" yine de eşleşiyor. Bu iki durum da kafa karıştırıcıdır ve beklediğiniz gibi değildir.

Doğru yaklaşımı benimseyen ve beklediğinizi yapan jQuery ile karşılaştırma yapmak faydalı olacaktır:

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

...bu semantik maskaralıkları çözmek için :scope yazın.

querySelector'i :scope ile düzeltme

WebKit, querySelector[All]()'te :scope sözde sınıfını kullanma desteğini yakın zamanda kullanıma sundu. Bu özelliği Chrome Canary 27'de test edebilirsiniz.

Seçicileri bir bağlam öğesiyle sınırlamak için kullanabilirsiniz. Bir örnekle açıklayalım. Aşağıda :scope, seçicinin kapsam öğesinin alt ağacını "kapsamı" için kullanılır. Doğru, kapsamı üç kez söyledim.

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

:scope kullanmak, querySelector() yöntemlerinin anlamını biraz daha tahmin edilebilir hale getirir ve jQuery gibi diğerlerinin zaten yaptığıyla uyumlu hale getirir.

Peki ya performans?

Henüz değil :(

qS/qSA'da :scope kullanmanın performansı artırıp artırmayacağını merak ediyorum. İyi bir mühendis gibi bir test hazırladım. Nedenimiz: Tarayıcının seçici eşleştirmesi yapması için daha az yüzey alanı, daha hızlı aramalar anlamına gelir.

Denememizde WebKit, şu anda :scope kullanmamaya kıyasla yaklaşık 1,5-2 kat daha uzun sürüyor. Lanet olsun! crbug.com/222028 düzeltildiğinde, bu özelliği kullanmamak yerine kullanmak teorik olarak size performans açısından küçük bir artış sağlayabilir.