Do czego służy pseudoklasa CSS „scope”?

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