:scope
se define en Selectores CSS 4 de la siguiente manera:
Es una pseudoclase que representa cualquier elemento que se encuentra en el conjunto de elementos de referencia contextual. Es un conjunto de elementos especificados de forma explícita (potencialmente vacío), como el que especifica
querySelector()
, o el elemento superior de un elemento<style scoped>
, que se usa para "aplicar el alcance" a un selector de modo que solo coincida dentro de un subárbol.
Un ejemplo de uso de esto es dentro de un <style scoped>
(más información):
<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>
Esto colorea los elementos li
en el primer ul
de color rojo y, debido a la regla :scope
, coloca un borde alrededor del ul
. Esto se debe a que, en el contexto de este <style scoped>
, ul
coincide con :scope
. Es el contexto local. Si agregáramos una regla :scope
en el <style>
externo, coincidiría con todo el documento. Esencialmente, equivale a :root
.
Elementos contextuales
Probablemente conoces la versión Element
de querySelector()
y querySelectorAll()
. En lugar de consultar todo el documento, puedes restringir el conjunto de resultados a un elemento contextual:
<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>
Cuando se los llama, el navegador muestra un NodeList
que está filtrado para incluir solo el conjunto de nodos a.) que coincide con el selector y b.) que también son subordinados del elemento de contexto. Por lo tanto, en el segundo ejemplo, el navegador encuentra todos los elementos a
y, luego, filtra los que no están en el elemento scope
. Esto funciona, pero puede generar un comportamiento extraño si no tienes cuidado. Más información.
Cuando querySelector falla
Hay un punto muy importante en la especificación de selectores que las personas suelen pasar por alto. Incluso cuando se invoca querySelector[All]()
en un elemento, los selectores se evalúan en el contexto de todo el documento. Esto significa que pueden ocurrir situaciones imprevistas:
scope.querySelectorAll('ul a').length); // 1
scope.querySelectorAll('body ul a').length); // 1
¿Qué rayos está pasando? En el primer ejemplo, ul
es mi elemento, pero aún puedo usarlo y coincide con los nodos. En el segundo, body
ni siquiera es un descendiente de mi elemento, pero "body ul a
" aún coincide. Ambas opciones son confusas y no son lo que esperas.
Vale la pena comparar con jQuery aquí, que toma el enfoque correcto y hace lo que esperas:
$(scope).find('ul a').length // 0
$(scope).find('body ul a').length // 0
…ingresa :scope
para resolver estos problemas semánticos.
Corrige querySelector con :scope
WebKit recientemente lanzó compatibilidad para usar la pseudoclase :scope
en querySelector[All]()
. Puedes probarlo en Chrome Canary 27.
Puedes usarlo para restringir los selectores a un elemento de contexto. Veamos un ejemplo. En el siguiente ejemplo, se usa :scope
para “aplicar el alcance” del selector al subárbol del elemento de alcance. Así es, dije alcance tres veces.
scope.querySelectorAll(':scope ul a').length); // 0
scope.querySelectorAll(':scope body ul a').length); // 0
scope.querySelectorAll(':scope a').length); // 1
El uso de :scope
hace que la semántica de los métodos querySelector()
sea un poco más predecible y esté alineada con lo que otros, como jQuery, ya hacen.
¿Mejoró el rendimiento?
Aún no :(
Me gustaría saber si usar :scope
en qS/qSA mejora el rendimiento. Como un buen ingeniero,
creé una prueba. Mi razonamiento: menos área de superficie para que el navegador realice la coincidencia del selector significa búsquedas más rápidas.
En mi experimento, WebKit actualmente tarda entre 1.5 y 2 veces más que si no se usara :scope
. ¡Demostraciones! Cuando se solucione crbug.com/222028, en teoría, deberías obtener un ligero aumento de rendimiento si lo usas en comparación con no usarlo.