:scope
jest zdefiniowany w 4 edycji selektorów arkusza CSS jako:
Pseudoklasa, która reprezentuje dowolny element znajdujący się w zbiorze elementów odniesienia kontekstowego. Jest to (potencjalnie pusty) określony zestaw elementów, np. określony przez
querySelector()
, lub element nadrzędny elementu<style scoped>
, który jest używany do „zakresu” selektora w taki sposób, aby pasował tylko w ramach drzewa podrzędnego.
Przykład użycia w elementach <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. Gdybyśmy dodali regułę :scope
na zewnętrznej stronie <style>
, pasowałaby ona do całego dokumentu. W podstawie jest to to samo co :root
.
Elementy kontekstowe
Pewnie znasz wersję Element
konfiguracji querySelector()
i 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>
Po ich wywołaniu przeglądarka zwraca identyfikator NodeList
przefiltrowany tak, aby uwzględniał tylko zestaw węzłów, które a.) pasują do selektora i b.), które są również elementami potomnymi elementu kontekstu. W drugim przykładzie przeglądarka znajduje 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 elementy są mylące i nieprawidłowe.
W tym artykule warto porównać się z biblioteką jQuery, która działa w prawidłowy sposób i działa w sposób zgodny 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 ją przetestować w Chrome Canary 27.
Możesz go użyć, aby ograniczyć selektory do elementu kontekstu. 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.
Czy to wpłynie na wydajność?
Jeszcze nie :(
Ciekawi mnie, czy użycie :scope
w QS i QSA poprawia 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 jego użycie powinno teoretycznie zwiększyć wydajność w porównaniu z nieużywaniem.