Почему этот фильтр CSS: not() не фильтруется?

Я хочу выбрать промежутки, которые не являются потомками определенного класса, и назовите его "нет". Здесь мой CSS:

div:not(.no) span{background-color:#00f;}

Здесь HTML

<div>
    <span>yes 1</span>
</div>
<div class="no">
        <span>no 1</span>
</div>
<div class="no">
    <div>
           <span>no 2</span>
    </div>
</div>

Два вопроса:

  • Почему мой CSS применим как к yes 1, так и к no 2?
  • Почему все это ломается, если я переключаюсь на универсальный селектор?

    *:not(.no) span{background-color:#00f;}
    

Здесь код в JSFiddle: http://jsfiddle.net/stephaniehobson/JtNZm/

Ответ 1

  • Оба элемента span элементов div элементов класса div не имеют класса no, независимо от того, есть ли у него какие-либо другие предки:

    <div> <!-- This is div:not(.no), pretty much a given -->
        <span>yes 1</span>
    </div>
    
    <div class="no"> <!-- In this case, although this is div.no... -->
        <div>        <!-- ... this is div:not(.no)! -->
               <span>no 2</span>
        </div>
    </div>
    
  • Оба html и body, которые являются предками ваших элементов div и span, удовлетворяют *:not(.no) при использовании универсального селектора (точнее, при отсутствии селектора типов). Это приведет к тому, что все ваши элементы span будут иметь цвет фона.

Одним из решений этого является привязка фильтра отрицания к элементу body с использованием детского комбинатора, если элементы верхнего уровня div всегда будут дочерними элементами body:

body > div:not(.no) span { background-color: #00f; }

jsFiddle demo

Другое решение - просто использовать стили переопределения.

Ответ 2

BoltClock является правильным. Это может иметь смысл, если вы произнесете селектор следующим образом:

Выберите любой элемент span
который происходит от элемента divзначение class не содержит слова no.

Каждый из выбранных span в вашем примере на самом деле происходит от div, значение class которого не содержит слова no - тот факт, что второе из них также происходит от a div, значение class которого содержит слово no, не отменяет (ha!) предыдущее утверждение.

Интересно, что я бы сказал, что если вы переместили второй no вниз на уровень, второй span по-прежнему будет соответствовать. CSS не имеет понятия близости к элементу, поэтому любому предшественнику div должно быть достаточно, чтобы соответствовать селектору, независимо от того, "ближе ли он" к span или нет.

Ответ 3

Я думаю, что лучший выбор - разделить ваше утверждение на 2:

div span { background-color:#00f; }
.no span { background-color:#fff; }

Вы можете увидеть эффект здесь: http://jsfiddle.net/JHTqp/