:not(selector) 가상 선택자는 매력적인 놈이지만 아래 한계를 인지하고 사용해야 한다.

  1. 중첩시킬 수 없다. :not(:not(...))

  2. 아무 영향을 미치지 않는 놈이 생길 수도 있다. :not(*)

  3. 아무 영향도 없지만 특정도(specificity)만 올리게 될 수 있다. #foo:not(#bar) 이 선택자를 보면, 모든 #foo#bar가 아니므로 #foo라고만 쓴 선택자와 동일하다. 그렇지만 특정도는 단순한 #foo보다 높다.

  4. :not(.foo).foo가 아닌 모든 것을 가리킨다. htmlbody까지 말이다.

  5. 이 선택자는 조상, 자손에 상속돼 적용되지 않는다.
    예컨대, body :not(table) a 선택자를 보자. 언뜻 생각하기에 이것은 table 안에 있는 a를 제외하는 규칙이다. 그러나 이 규칙은 여전히 table 안의 a에 적용된다. 왜냐하면 a의 조상중 하나인 trtable이 아니기 때문이다.
    :not(article) p 역시 article 밑의 p를 제외해야 할 것 같지만 여전히 제외되지 않고 article의 자손인 p에 적용된다. p의 조상중 하나인 bodyarticle이 아니기 때문이다. 그래서 사실상 :not(article) p는 모든 p를 가리키게 된다.
    같은 맥락에서 :not(article) > p는 의도대로 작동한다. article이 아닌 요소(element)의 바로 밑에 있는(자식) p에만 적용하라는 뜻이기 때문에 :not(article)p 사이에 다른 요소가 낄 여지가 없고, p의 먼 조상이 영향을 미치지도 않기 때문이다.

  6. 한 번에 두 선택자를 쓰는 건 현재 브라우저 지원이 충분치 않다. 예컨대 :not(.foo, .bar) 보다는 :not(.foo):(.bar) 형식으로 쓰는 게 낫다.

왜 찾게 됐냐면…

인용문 안의 헤딩을 제외할 요량으로 :not(blockquote) h2 선택자를 사용했는데 뜻대로 되지 않았다. 위의 5번 규칙에 해당하기 때문이다. 그래… h2의 조상 중에는 blockquote이 아닌 것이 아주 많았던 것이다.

MDN에서 위 항목중 5번을 찾았는데 알아듣기 어렵게 돼 있어서 5번 설명을 내가 대폭 보강했다. 나머지는 MDN의 설명을 대체로 그대로 번역한 것이다. (현재 시점에서 MDN :not 문서의 한국어 번역은 별로 좋지 않다. 따라서 영어 문서를 보기를 권한다.)