CSS :scope 의사 클래스는 어디에 사용되나요?

:scopeCSS 선택자 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>

이렇게 하면 첫 번째 ulli 요소가 빨간색으로 표시되고 :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이 수정되면 이 기능을 사용하면 사용하지 않는 것보다 이론적으로 성능이 약간 향상됩니다.