:scope
은 CSS 선택자 4에 다음과 같이 정의되어 있습니다.
문맥 참조 요소 집합에 있는 모든 요소를 나타내는 가상 클래스입니다. 이는 명시적으로 지정된 요소 집합 (예:
querySelector()
또는<style scoped>
요소의 상위 요소)으로, 비어 있을 수 있습니다. 이 요소는 하위 트리 내에서만 일치하도록 선택기의 '범위'를 지정하는 데 사용됩니다.
<style scoped>
내에서 이를 사용하는 예는 다음과 같습니다(자세한 내용).
<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>
이렇게 하면 첫 번째 ul
의 li
요소가 빨간색으로 표시되고 :scope
규칙으로 인해 ul
주위에 테두리가 배치됩니다. 이 <style scoped>
의 컨텍스트에서 ul
가 :scope
와 일치하기 때문입니다. 로컬 컨텍스트입니다. 외부 <style>
에 :scope
규칙을 추가하면 전체 문서와 일치합니다. 기본적으로 :root
와 같습니다.
문맥 요소
querySelector()
및 querySelectorAll()
의 Element
버전을 알고 계실 겁니다. 전체 문서를 쿼리하는 대신 결과 집합을 문맥 요소로 제한할 수 있습니다.
<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>
이러한 메서드가 호출되면 브라우저는 a.) 선택자와 일치하고 b.) 컨텍스트 요소의 자손인 노드 집합만 포함하도록 필터링된 NodeList
를 반환합니다. 따라서 두 번째 예에서는 브라우저가 모든 a
요소를 찾은 다음 scope
요소에 없는 요소를 필터링합니다. 이렇게 하면 작동하지만 주의하지 않으면 이상한 동작이 발생할 수 있습니다. 읽어보세요.
querySelector가 잘못된 경우
선택기 사양에는 사람들이 종종 간과하는 매우 중요한 사항이 있습니다. 요소에서 querySelector[All]()
이 호출되더라도 선택기는 여전히 전체 문서의 컨텍스트에서 평가됩니다. 따라서 예상치 못한 일이 발생할 수 있습니다.
scope.querySelectorAll('ul a').length); // 1
scope.querySelectorAll('body ul a').length); // 1
WTF! 첫 번째 예에서 ul
는 요소이지만 여전히 사용할 수 있고 노드를 일치시킬 수 있습니다. 두 번째 예에서는 body
가 요소의 자손도 아니지만 'body ul a
'는 여전히 일치합니다. 둘 다 혼란스럽고 예상치 못한 결과입니다.
여기서는 올바른 접근 방식을 사용하고 예상대로 작동하는 jQuery와 비교해 볼 가치가 있습니다.
$(scope).find('ul a').length // 0
$(scope).find('body ul a').length // 0
...의미론적 표현을 해결하려면 :scope
를 입력합니다.
:scope를 사용하여 querySelector 수정
WebKit은 querySelector[All]()
에서 :scope
가상 클래스를 사용하는 지원을 최근에 출시했습니다. Chrome Canary 27에서 테스트할 수 있습니다.
이를 사용하여 선택기를 컨텍스트 요소로 제한할 수 있습니다. 예를 살펴보겠습니다. 다음에서 :scope
는 범위 요소의 하위 트리로 선택기의 '범위를 지정'하는 데 사용됩니다. 맞습니다. 범위를 세 번 말씀드렸습니다.
scope.querySelectorAll(':scope ul a').length); // 0
scope.querySelectorAll(':scope body ul a').length); // 0
scope.querySelectorAll(':scope a').length); // 1
:scope
를 사용하면 querySelector()
메서드의 시맨틱을 좀 더 예측 가능하게 만들고 jQuery와 같은 다른 도구에서 이미 실행 중인 작업과 일치시킬 수 있습니다.
실적 향상 여부
아직은 안 됩니다 :(
qS/qSA에서 :scope
을 사용하면 성능이 향상되는지 궁금했습니다. 그래서 저는 훌륭한 엔지니어답게 테스트를 작성했습니다. 근거: 브라우저에서 선택기 일치를 수행할 노출 영역이 적을수록 조회 속도가 빨라집니다.
제 실험에서 WebKit은 현재 :scope
를 사용하지 않을 때보다 1.5~2배 더 오래 걸립니다. 아, 저런! crbug.com/222028이 수정되면 이 기능을 사용하면 사용하지 않는 것보다 이론적으로 성능이 약간 향상됩니다.