브라우저가 CSS 선택기와 오른쪽에서 왼쪽으로 일치하는 이유는 무엇입니까?


560

CSS 선택기는 오른쪽에서 왼쪽으로 브라우저 엔진과 일치합니다. 그래서 그들은 먼저 아이들을 찾은 다음 부모가 규칙의 나머지 부분과 일치하는지 확인합니다.

  1. 왜 이런거야?
  2. 스펙이 말했기 때문입니까?
  3. 왼쪽에서 오른쪽으로 평가 된 경우 최종 레이아웃에 영향을 줍니까?

나에게 가장 간단한 방법은 요소 수가 가장 적은 선택기를 사용하는 것입니다. 따라서 ID는 먼저 1 요소 만 반환해야하므로 ID가 우선합니다. 그런 다음 가장 적은 수의 노드를 가진 클래스 나 요소 일 수 있습니다. 예를 들어 페이지에 하나의 범위 만있을 수 있으므로 범위를 참조하는 규칙을 사용하여 해당 노드로 직접 이동하십시오.

내 주장을 뒷받침하는 몇 가지 링크가 있습니다.

  1. http://code.google.com/speed/page-speed/docs/rendering.html
  2. https://developer.mozilla.org/en/Writing_Efficient_CSS

그것은 하나의 아이의 모든 부모보다는 부모의 모든 아이 (많을 수도 있음)를 보지 않아도되도록 이런 식으로 수행되는 것처럼 들립니다. DOM이 깊어도 RTL 일치에서 여러 노드가 아닌 레벨 당 하나의 노드 만 봅니다. CSS 선택기 LTR 또는 RTL을 평가하는 것이 더 쉽고 빠릅니까?


5
3. 아니오-읽는 방법에 관계없이 선택기는 항상 동일한 요소 세트와 일치합니다.
Šime Vidas

39
가치있는 것으로 브라우저는 사용자의 ID가 고유하다고 가정 할 수 없습니다. DOM 전체에 동일한 id = "foo"를 붙일 수 있으며 #foo선택기는 모든 노드와 일치해야합니다. jQuery는 $ ( "# foo")는 자체 규칙으로 자체 API를 정의하기 때문에 항상 하나의 요소 만 반환한다고 말할 수 있습니다. 그러나 브라우저는 CSS를 구현해야하며 CSS는 문서의 모든 것을 주어진 ID로 일치시킵니다.
Boris Zbarsky

4
@Quentin "부적합한"(HTML로) 문서 ID는 고유하지 않을 수 있으며 이러한 문서에서 CSS는 모든 요소를 ​​해당 ID와 일치시켜야합니다. CSS 자체는 고유 한 ID에 대한 규범 적 요구 사항을 제시하지 않습니다. 인용하는 텍스트는 유익합니다.
Boris Zbarsky

5
@Boris Zbarsky jQuery의 기능은 jQuery 내의 코드 경로에 따라 다릅니다. 경우에 따라 jQuery는 NodeSelector API (native querySelectorAll)를 사용합니다. 다른 경우에는 Sizzle이 사용됩니다. Sizzle는 여러 ID와 일치하지 않지만 QSA는 (AYK) 일치합니다. 선택 경로, 선택기, 컨텍스트 및 브라우저 및 버전에 따라 다릅니다. jQuery의 Query API는 "Native First, Dual Approach"라는 것을 사용합니다. 나는 그것에 관한 기사를 썼다. 그러나 그것은 아래로 떨어졌다. : 당신이 여기에서 찾을 수 있습니다 비록 fortybelow.ca/hosted/dhtmlkitchen/JavaScript-Query-Engines.html
개렛

5
나는 아무도 확신하지 못하지만 두 사람은이 긴 대화에서 무슨 일이 일어나고 있는지 알아낼 수 있습니다. 우리는 이러한 확장 된 토론을 위해 대화를 나눕니다. 실제로 정보를 명확하게 설명하려는 경우 실제로 유지하려는 내용은 질문이나 답변에 포함되어야합니다. 스택 오버플로는 주석의 토론을 잘 처리하지 못합니다.
George Stocker

답변:


824

브라우저가 선택자 일치를 수행 할 때 하나의 요소 (스타일을 결정하려는 요소)와 모든 규칙 및 선택자가 있으며 요소와 일치하는 규칙을 찾아야합니다. 예를 들어 하나의 선택기가 있고 해당 선택기와 일치하는 모든 요소를 ​​찾아야하는 일반적인 jQuery와 다릅니다.

선택기와 비교할 하나의 선택기와 하나의 요소 만있는 경우 왼쪽에서 오른쪽으로 더 의미가 있습니다. 그러나 그것은 브라우저의 상황이 아닙니다 . 브라우저가 Gmail 또는 다른 것을 렌더링 <span>하려고 시도하고 스타일을 지정하려는 스타일과 Gmail이 스타일 시트에 넣은 10,000 개 이상의 규칙을 가지고 있습니다 (나는 그 숫자를 만들지 않습니다).

특히, 브라우저가 고려중인 대부분의 선택기를보고있는 상황에서는 해당 요소와 일치 하지 않는 것으로 간주됩니다 . 따라서 문제는 선택기가 가능한 빨리 일치하지 않는다는 결정 중 하나가됩니다. 일치하는 경우에 약간의 추가 작업이 필요한 경우 일치하지 않는 경우에 저장 한 모든 작업으로 인해 여전히 승리합니다.

선택기의 가장 오른쪽 부분을 요소와 일치시키는 것으로 시작하면 일치하지 않을 가능성이 있습니다. 일치하는 경우 더 많은 작업을 수행해야하지만 대부분의 경우 그리 크지 않은 나무 깊이에 비례합니다.

반면, 선택기의 가장 왼쪽 부분을 일치시켜 시작하면 ... 어떻게 일치합니까? DOM을 걷기 시작하고 DOM과 일치하는 노드를 찾으십시오. 가장 왼쪽 부분에 일치하는 항목이 없다는 것을 발견하면 시간이 걸릴 수 있습니다.

브라우저는 오른쪽에서 일치합니다. 그것은 분명한 출발점을 제공하며 대부분의 후보 선택기를 매우 빨리 제거 할 수 있습니다. http://groups.google.com/group/mozilla.dev.tech.layout/browse_thread/thread/b185e455a0b3562a/7db34de545c17665 에서 일부 데이터를 볼 수 있지만 (노트가 혼동 되기는하지만) 결과는 특히 Gmail에 대한 것입니다. 2 년 전에 (규칙, 요소) 쌍의 70 %에 대해 규칙의 가장 오른쪽 선택기의 태그 / 클래스 / ID 부분 만 검사 한 후 규칙이 일치하지 않는 것으로 결정할 수 있습니다. Mozilla의 페이지로드 성능 테스트 스위트의 해당 숫자는 72 %입니다. 따라서 가능한 한 빨리 모든 규칙의 2/3를 제거하고 나머지 1/3과 일치하는 것에 대해서만 걱정할 가치가 있습니다.

또한 정확히 일치하지 않는 규칙을 일치시키려는 시도를 피하기 위해 브라우저가 이미 수행 한 다른 최적화가 있습니다. 예를 들어, 가장 오른쪽 선택자에 id가 있고 해당 id가 요소의 id와 일치하지 않으면 Gecko에서 해당 요소와 해당 선택자를 일치시키지 않습니다. 시도한 "ID가있는 선택기"세트 요소의 ID에 대한 해시 테이블 조회에서 제공됩니다. 따라서 규칙의 70 % 는 가장 오른쪽 선택기의 태그 / 클래스 / ID 만 고려한 후에도 여전히 일치 하지 않을 가능성이 큰 규칙입니다 .


5
약간의 보너스로 영어로도 LTR보다 RTL을 읽는 것이 더 합리적입니다. 예 : stackoverflow.com/questions/3851635/css-combinator-precedence/…
BoltClock

6
참고 RTL의 일치에만 걸쳐 적용 콤비 . 간단한 선택기 수준으로 드릴 다운하지 않습니다. 즉, 브라우저는 가장 오른쪽에있는 복합 선택기 또는 간단한 선택기 시퀀스를 가져 와서 원자 적으로 일치 시키려고 시도합니다. 그런 다음 일치하는 항목이 있으면 컴비 네이터를 따라 왼쪽의 다음 복합 선택기로 이동 하여 해당 위치의 요소 등을 확인합니다. 브라우저가 복합 선택기 RTL의 각 부분을 읽었다는 증거는 없습니다. 사실, 마지막 단락은 정확하게 그렇지 않다는 것을 보여줍니다 (아이디 체크는 항상 우선합니다).
BoltClock

5
사실, 적어도 Gecko에서는 선택기와 일치 할 때까지 태그 이름과 네임 스페이스가 우선합니다. ID (태그 이름 및 클래스 이름)는 사전 필터링 단계에서 고려되며 실제로 선택기와 일치하지 않고 대부분의 규칙을 제거합니다.
Boris Zbarsky

UA가 수행하는 최적화에 따라 도움 이 수 있지만 위에서 설명한 Gecko I의 사전 필터링 단계에는 도움이되지 않습니다. 하위 컴비 네이터에 사용되는 ID 및 클래스에 대해 작동하는 두 번째 필터링 단계가 있지만 도움이 될 수 있습니다.
Boris Zbarsky

@ Benito Ciaro : 특이성 문제는 말할 것도 없습니다.
BoltClock

33

상향식 구문 분석이라고도하는 오른쪽에서 왼쪽 구문 분석 은 실제로 브라우저에 효율적입니다.

다음을 고려하세요:

#menu ul li a { color: #00f; }

브라우저에 먼저 확인 a한 후, li다음 ul, 다음 #menu.

브라우저가 페이지를 스캔 할 때 현재 요소 / 노드와 스캔 한 모든 이전 노드 / 요소를보기 만하면되기 때문입니다.

주목해야 할 것은 브라우저가 완전한 태그 / 노드를 얻는 순간부터 처리를 시작 하고 스크립트를 찾을 때를 제외하고 전체 페이지를 기다릴 필요가 없다는 것입니다.이 경우 스크립트는 일시적으로 일시 중지되고 스크립트 실행이 완료됩니다. 앞으로 나아갑니다.

다른 방법으로 진행하는 경우 브라우저가 첫 번째 검사에서 스캔 한 요소를 찾았지만 모든 추가 선택기의 문서를 계속 찾아야했기 때문에 비효율적입니다. 이를 위해 브라우저는 전체 HTML을 가져야하며 CSS 페인팅을 시작하기 전에 전체 페이지를 스캔해야 할 수도 있습니다.

이것은 대부분의 라이브러리가 dom을 구문 분석하는 방식과 반대입니다. dom이 구성되어 있으며 전체 페이지를 스캔 할 필요가 없습니다. 첫 번째 요소를 찾은 다음 다른 요소와 일치시킵니다.


20

더 구체적에서 덜 구체적으로 계단식으로 연결할 수 있습니다. 또한 응용 프로그램에서 단락을 허용합니다. 상위 규칙이 적용되는 모든 측면에보다 구체적인 규칙이 적용되면 모든 상위 규칙이 무시됩니다. 부모에 다른 비트가 있으면 적용됩니다.

반대로 돌아 가면 부모에 따라 서식을 지정한 다음 아이가 다른 것을 가질 때마다 덮어 씁니다. 장기적으로 이것은 이미 처리 된 규칙에서 항목을 무시하는 것보다 훨씬 많은 작업입니다.


11
그것은 별도의 문제입니다. 특정 순서로 규칙을 정렬 한 다음 특정 순서로 규칙을 일치시켜 계단식 배열을 수행합니다. 그러나 여기서 질문은 주어진 규칙에 대해 특정 방식으로 선택기와 일치하는 이유입니다.
Boris Zbarsky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.