:scope jest zdefiniowany w 4 edycji selektorów arkusza CSS jako:
Pseudoklasa, która reprezentuje dowolny element należący do zestawu elementów referencyjnych kontekstowych. Jest to (potencjalnie pusty) zestaw elementów określony jawnie, np. przez
querySelector()lub element nadrzędny elementu<style scoped>, który służy do „ograniczenia” selektora tak, aby pasował tylko w poddrzewie.
Przykład użycia tego elementu w komponencie <style scoped> (więcej informacji):
<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>
W ten sposób elementy li w pierwszym ul będą miały kolor czerwony, a ze względu na regułę :scope wokół ul będzie widoczne obramowanie. Dzieje się tak, ponieważ w kontekście tego <style scoped> element ul pasuje do elementu :scope. Jest to kontekst lokalny. Jeśli dodamy regułę :scope w zewnętrznym <style>, będzie ona pasować do całego dokumentu. W podstawie jest to to samo co :root.
Elementy kontekstowe
Zapewne znasz wersję Element parametru querySelector() i parametr querySelectorAll(). Zamiast wysyłać zapytanie do całego dokumentu, możesz ograniczyć zbiór wyników do elementu kontekstowego:
<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>
Gdy są wywoływane, przeglądarka zwraca NodeList, który jest filtrowany tak, aby zawierać tylko zestaw węzłów, które: a) pasują do selektora i b) są też potomkami elementu kontekstu. W drugim przykładzie przeglądarka wyszukuje wszystkie elementy a, a potem odfiltrowuje te, które nie znajdują się w elemencie scope. To działa, ale jeśli nie zachowasz ostrożności, może to spowodować dziwne zachowanie. Czytaj dalej.
Gdy querySelector nie działa prawidłowo
W specyfikacji selektorów jest bardzo ważny punkt, który często jest pomijany. Nawet gdy querySelector[All]() jest wywoływane w elemencie, selektory są nadal oceniane w kontekście całego dokumentu. Może to spowodować nieoczekiwane skutki:
scope.querySelectorAll('ul a').length); // 1
scope.querySelectorAll('body ul a').length); // 1
WTF! W pierwszym przykładzie ul jest moim elementem, ale nadal mogę go używać i dopasowywać do węzłów. W drugim przypadku body nie jest nawet potomkiem mojego elementu, ale „body ul a” nadal pasuje. Oba te rozwiązania są mylące i nie takie, jakich oczekujesz.
Warto tu porównać jQuery, które stosuje właściwe podejście i działa zgodnie z oczekiwaniami:
$(scope).find('ul a').length // 0
$(scope).find('body ul a').length // 0
…wpisz :scope, aby rozwiązać te semantyczne sztuczki.
Naprawianie funkcji querySelector za pomocą atrybutu :scope
WebKit niedawno wprowadził obsługę pseudoklasy :scope w querySelector[All](). Możesz go przetestować w Chrome Canary 27.
Możesz go użyć, aby ograniczyć selektory do elementu kontekstowego. Zobaczmy przykład. W poniższym przykładzie :scope służy do „ograniczenia” zakresu selektora do poddrzewa elementu zakresu. Zgadza się, powiedziałem „zakres” 3 razy.
scope.querySelectorAll(':scope ul a').length); // 0
scope.querySelectorAll(':scope body ul a').length); // 0
scope.querySelectorAll(':scope a').length); // 1
Dzięki temu semantyka metod querySelector() jest nieco bardziej przewidywalna i zgodna z tym, co robią inne biblioteki, np. jQuery.:scope
Zwycięskie wyniki?
Jeszcze nie :(
Zastanawiam się, czy użycie :scope w qS/qSA zwiększa wydajność. Jako dobry inżynier stworzyłem test. Uzasadnienie: mniejsza powierzchnia, na której przeglądarka ma dopasowywać selektor, oznacza szybsze wyszukiwanie.
W moim eksperymencie WebKit potrzebuje obecnie 1, 5–2 razy więcej czasu niż bez :scope. O kurczę! Gdy crbug.com/222028 zostanie naprawiony, w teorii korzystanie z niego powinno teoretycznie zapewnić niewielki wzrost wydajności w porównaniu z nieużywaniem.