Предполагается, что селектор CSS: not() должен работать с отдаленными потомками?

Вот официальная документация для псевдо-класса CSS3 :not():
http://www.w3.org/TR/css3-selectors/#negation
и предлагаемые улучшения CSS Selectors Level 4:
http://dev.w3.org/csswg/selectors4/#negation

Я искал реализацию и поддержку браузера для :not(), но единственные примеры, которые я нашел, были с одним элементом или с прямым дочерним элементом элемента, например:

div *:not(p) { color: red; }

Приведенный выше пример работает, когда <p> является прямым дочерним элементом <div>, но он не работает, когда <p> является более отдаленным потомком <div>.

div :not(p) {
    color: red;
}
<div>
    <ul>
        <li>This is red</li>
    </ul>
    <p>This is NOT</p>
    <blockquote><p>This is red but is not supposed to be!</p></blockquote>
</div>

Ответ 1

Должен ли он работать так, как я думаю, он должен?

Нет, поведение, которое вы видите, верное.

В вашем последнем примере, хотя <blockquote> содержит <p>, он сам <blockquote>, который соответствует *:not(p), а также условие, что он должен быть потомком <div>, который он является. Стиль применяется только к <blockquote>, но затем он наследуется <p> внутри него.

Элемент <p> по-прежнему считается против отрицания, поэтому сам <p> по-прежнему исключается из вашего селектора. Он просто наследует цвет текста от его родителя, элемент <blockquote>.

Даже если ни один из его относительно близких предков не подходил к селектору, вы также должны беспокоиться о таких элементах, как html и body, хотя вы могли бы вначале просто нажать на селектор body:

body div...

Вот почему я часто настоятельно рекомендую использовать селектор :not() для фильтрации потомков, особенно если он не квалифицирован с помощью селектора типов (например, div в вашем примере). Это не работает так, как этого ожидают многие люди, а использование унаследованных свойств, таких как color, служит только для того, чтобы усугубить проблему, в то же время сделать ее еще более запутанной для авторов. См. Мои ответы на эти другие вопросы для получения дополнительных примеров:

Решение описанной проблемы - это просто применить другой цвет к элементам <p>. Вы не сможете просто исключить их с помощью селектора из-за наследования:

/* Apply to div and let all its descendants inherit */
div {
  color: red;
}

/* Remove it from div p */
div p {
  color: black;
}

On Selectors Level 4: yes, :not() действительно расширен, чтобы принимать полные сложные селектора, содержащие комбинаторы. По сути, это означает, что (как только браузер начнет ее внедрять), вы сможете написать следующий селектор и выполнить его именно то, что вы хотите:

p:not(div p) {
  color: red;
}

В случае, если кто-то заинтересован, это работает сегодня в jQuery.

Ответ 2

Цвет присваивается blockquote, а затем наследуется p.

:not(p) просто делает так, чтобы стили не применялись напрямую. Они все еще унаследованы.