Nei selettori CSS 4, :scope
viene definito come:
Una pseudo-classe che rappresenta qualsiasi elemento presente nell'insieme di elementi di riferimento contestuale. Si tratta di un insieme di elementi (potenzialmente vuoto) specificati esplicitamente, come quello specificato da
querySelector()
o l'elemento principale di un elemento<style scoped>
, che viene utilizzato per "ambito" un selettore in modo che corrisponda solo all'interno di un sottoalbero.
Un esempio di utilizzo di questa funzionalità è all'interno di un elemento <style scoped>
(ulteriori informazioni):
<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>
In questo modo gli elementi li
nel primo ul
vengono colorati di rosso e, a causa della regola :scope
, viene inserito un bordo intorno a ul
. Questo perché nel contesto di questo <style scoped>
, ul
corrisponde a :scope
. ma il contesto locale. Se aggiungessimo una regola :scope
nella sezione <style>
esterna, verrebbe applicata all'intero documento. In pratica, equivalente a :root
.
Elementi contestuali
Probabilmente conosci la versione Element
di querySelector()
e querySelectorAll()
. Anziché eseguire query sull'intero documento, puoi limitare l'insieme di risultati a un elemento contestuale:
<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>
Quando vengono richiamate, il browser restituisce un valore NodeList
filtrato in modo da includere solo il set di nodi a.) che corrispondono al selettore e b.) anch'essi discendenti dell'elemento di contesto. Quindi nel secondo esempio, il browser trova tutti gli elementi a
e filtra quelli non presenti nell'elemento scope
. Questa regola funziona, ma può portare a comportamenti bizzarri se non fai attenzione. Continua a leggere.
Quando querySelector non funziona
C'è un punto davvero importante nelle specifiche dei selettori che spesso le persone trascurano. Anche quando querySelector[All]()
viene richiamato su un elemento, i selettori continuano a valutare nel contesto dell'intero documento. Ciò significa che possono accadere cose inaspettate:
scope.querySelectorAll('ul a').length); // 1
scope.querySelectorAll('body ul a').length); // 1
Wow! Nel primo esempio, ul
è il mio elemento, ma posso ancora utilizzarlo e corrisponde ai nodi. Nel secondo, body
non è nemmeno un discendente del mio elemento, ma "body ul a
" corrisponde comunque. Entrambi sono confusi e non corrispondono alle aspettative.
In questo caso, vale la pena fare un confronto con jQuery, che adotta l'approccio giusto e fa ciò che ci si aspetta:
$(scope).find('ul a').length // 0
$(scope).find('body ul a').length // 0
... inserisci :scope
per risolvere questi imbrogli semantici.
Correzione di querySelector con :scope
WebKit ha recentemente ottenuto il supporto per l'utilizzo della pseudo-classe :scope
in querySelector[All]()
. Puoi testarlo in Chrome Canary 27.
Puoi utilizzarlo per limitare i selettori a un elemento di contesto. Vediamo un esempio. Di seguito, viene utilizzato :scope
per "applicare" il selettore al sottoalbero dell'elemento di ambito. Esatto, ho detto scope tre volte!
scope.querySelectorAll(':scope ul a').length); // 0
scope.querySelectorAll(':scope body ul a').length); // 0
scope.querySelectorAll(':scope a').length); // 1
L'utilizzo di :scope
rende la semantica dei metodi querySelector()
un po' più prevedibile e in linea con ciò che stanno già facendo altri come jQuery.
Prestazioni efficaci?
Non ancora :(
Mi chiedevo se l'uso di :scope
in qS/qSA migliora le prestazioni. Quindi... da bravo ingegnere ho condotto un test. La mia motivazione: una minore superficie di esplorazione da parte del browser per la corrispondenza del selettore significa ricerche più veloci.
Nel mio esperimento, al momento WebKit richiede circa 1,5-2 volte in più rispetto al mancato utilizzo di :scope
. Dramma! Quando crbug.com/222028 viene risolto, il suo utilizzo dovrebbe teoricamente migliorare le prestazioni rispetto al suo mancato utilizzo.