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. Seçicinin yalnızca bir alt ağaçta eşleşmesi için "kapsamını" belirlemek amacıyla 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ıya boyar ve :scope kuralı nedeniyle ul 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. Esasen :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 tuhaf davranışlarla karşılaşabilirsiniz. Okumaya devam edin.

querySelector yanlış gittiğinde

Seçiciler spesifikasyonunda, kullanıcıların genellikle gözden kaçırdığı çok ö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 öğemdir ancak yine de kullanabilir ve düğümlerle eşleştirebilirim. İkinci örnekte 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 anlamsal saçmalı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, seçiciyi kapsam öğesinin alt ağacına "kapsamlamak" için :scope 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.

Performans kazancı mı?

Henüz değil :(

qS/qSA'da :scope kullanılmasının performansı artırıp artırmadığını merak ediyorum. İyi bir mühendis gibi bir test hazırladım. Gerekçem: Tarayıcının seçici eşleştirmesi 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.