Wozu dient die CSS-„:scope“-Pseudoklasse?

:scope ist in CSS-Selektoren 4 folgendermaßen definiert:

Eine Pseudoklasse, die jedes Element darstellt, das sich im Kontext-Referenzelementsatz befindet. Dies ist ein (möglicherweise leerer) explizit angegebener Satz von Elementen, z. B. der durch querySelector() oder das übergeordnete Element eines <style scoped>-Elements angegebene, das verwendet wird, um einen Selektor zu bestimmen, sodass er nur innerhalb einer Unterstruktur übereinstimmt.

Ein Beispiel für die Verwendung dieser Funktion finden Sie in einem <style scoped> (weitere Informationen):

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

Dadurch werden die li-Elemente im ersten ul rot eingefärbt und aufgrund der :scope-Regel wird ein Rahmen um ul gesetzt. Das liegt daran, dass die ul im Kontext von <style scoped> mit :scope übereinstimmt. Es ist der lokale Kontext. Wenn wir eine :scope-Regel in der äußeren <style> hinzufügen würden, würde sie mit dem gesamten Dokument übereinstimmen. Entspricht im Wesentlichen :root.

Kontextelemente

Wahrscheinlich kennst du die Element-Version von querySelector() und querySelectorAll(). Anstatt das gesamte Dokument abzufragen, können Sie die Ergebnismenge auf ein kontextbezogenes Element beschränken:

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

Werden diese aufgerufen, gibt der Browser ein NodeList-Objekt zurück, das so gefiltert wird, dass nur die Knoten eingeschlossen werden, die a.) mit dem Selektor übereinstimmen und b.) die auch Nachfolger des Kontextelements sind. Im zweiten Beispiel findet der Browser alle a-Elemente und filtert dann diejenigen heraus, die nicht im scope-Element enthalten sind. Das funktioniert, kann aber zu seltsamem Verhalten führen, wenn Sie nicht aufpassen. Lesen Sie weiter.

Wenn der QuerySelector schiefgeht

Die Spezifikation für Selektoren enthält einen wirklich wichtigen Punkt, den Nutzer häufig übersehen. Auch wenn querySelector[All]() für ein Element aufgerufen wird, werden Selektoren immer noch im Kontext des gesamten Dokuments ausgewertet. Das bedeutet, dass unvorhergesehene Dinge eintreten können:

    scope.querySelectorAll('ul a').length); // 1
    scope.querySelectorAll('body ul a').length); // 1

Was soll das? Im ersten Beispiel ist mein Element ul. Ich kann es aber trotzdem verwenden und zu Knoten hinzufügen. Im zweiten Fall ist body nicht einmal ein Nachfolger meines Elements, aber „body ul a“ stimmt noch überein. Beides ist verwirrend und entspricht nicht dem, was Sie erwarten.

Hier ein Vergleich mit jQuery, das den richtigen Ansatz verfolgt und das tut, was Sie erwarten:

    $(scope).find('ul a').length // 0
    $(scope).find('body ul a').length // 0

...geben Sie :scope ein, um diese semantischen Hürden zu lösen.

Korrektur von querySelector mit :scope

WebKit hat vor Kurzem Unterstützung für die Verwendung der Pseudoklasse :scope in querySelector[All]() erhalten. Sie kann in Chrome Canary 27 getestet werden.

Sie können Selektoren auf ein Kontextelement beschränken. Sehen wir uns ein Beispiel an. Im Folgenden wird :scope verwendet, um den Selektor auf die Unterstruktur des Bereichselements zu beschränken. Das stimmt. Ich habe den Umfang dreimal genannt!

    scope.querySelectorAll(':scope ul a').length); // 0
    scope.querySelectorAll(':scope body ul a').length); // 0
    scope.querySelectorAll(':scope a').length); // 1

Mit :scope wird die Semantik der querySelector()-Methoden etwas berechenbarer und entspricht dem, was andere wie jQuery bereits tun.

Leistungssteigerung?

Noch nicht :(

Ich würde gerne wissen, ob die Verwendung von :scope in qS/qSA eine Leistungssteigerung bewirkt. Also ... ich habe wie ein guter Entwickler einen Test erstellt. Meine Begründung: Wenn der Browser weniger Fläche für den Selektorabgleich hat, führt das zu einer schnelleren Suche.

In meinem Test dauert WebKit derzeit etwa 1, 5- bis 2-mal länger als :scope. dramatisch! Nachdem das Problem auf crbug.com/222028 behoben wurde, kann die Nutzung der Website theoretisch zu einem leichten Leistungsschub führen, statt sie nicht zu verwenden.