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