Почему мой селектор jQuery:not() не работает в CSS?
У меня есть этот макет:
<div id="sectors">
<h1>Sectors</h1>
<div id="s7-1103" class="alpha"></div>
<div id="s8-1104" class="alpha"></div>
<div id="s1-7605" class="beta"></div>
<div id="s0-7479"></div>
<div id="s2-6528" class="gamma"></div>
<div id="s0-4444"></div>
</div>
С этими правилами CSS:
#sectors {
width: 584px;
background-color: #ffd;
margin: 1.5em;
border: 4px dashed #000;
padding: 16px;
overflow: auto;
}
#sectors > h1 {
font-size: 2em;
font-weight: bold;
text-align: center;
}
#sectors > div {
float: left;
position: relative;
width: 180px;
height: 240px;
margin: 16px 0 0 16px;
border-style: solid;
border-width: 2px;
}
#sectors > div::after {
display: block;
position: absolute;
width: 100%;
bottom: 0;
font-weight: bold;
text-align: center;
text-transform: capitalize;
background-color: rgba(255, 255, 255, 0.8);
border-top: 2px solid;
content: attr(id) ' - ' attr(class);
}
#sectors > div:nth-of-type(3n+1) {
margin-left: 0;
}
#sectors > div.alpha { color: #b00; background-color: #ffe0d9; }
#sectors > div.beta { color: #05b; background-color: #c0edff; }
#sectors > div.gamma { color: #362; background-color: #d4f6c3; }
Я использую JQuery, чтобы добавить unassigned
класс для секторов, которые в противном случае не имеют одного из классов alpha
, beta
или же gamma
:
$('#sectors > div:not(.alpha, .beta, .gamma)').addClass('unassigned');
Затем я применяю некоторые другие правила к этому классу:
#sectors > div.unassigned {
color: #808080;
background-color: #e9e9e9;
opacity: 0.5;
}
#sectors > div.unassigned::after {
content: attr(id) ' - Unassigned';
}
#sectors > div.unassigned:hover {
opacity: 1.0;
}
И все работает безупречно в современных браузерах.
Интерактивный предварительный просмотр jsFiddle
Но видя как :not()
Селектор в JQuery основан на :not()
в CSS3 я думал, что смогу переместить его непосредственно в мою таблицу стилей, чтобы мне не пришлось полагаться на добавление дополнительного класса с использованием jQuery. Кроме того, я не очень заинтересован в поддержке старых версий IE, а другие браузеры имеют отличную поддержку :not()
селектор.
Поэтому я пытаюсь изменить .unassigned
часть выше к этому (зная, что у меня будут только сектора Α, Β и Γ в моем макете):
#sectors > div:not(.alpha, .beta, .gamma) {
color: #808080;
background-color: #e9e9e9;
opacity: 0.5;
}
#sectors > div:not(.alpha, .beta, .gamma)::after {
content: attr(id) ' - Unassigned';
}
#sectors > div:not(.alpha, .beta, .gamma):hover {
opacity: 1.0;
}
Но как только я это делаю, он перестает работать - во всех браузерах! Мои неназначенные сектора больше не отображаются серым цветом, затемняются или помечаются как "Неназначенные".
Обновленный, но не очень интерактивный предварительный просмотр jsFiddle
Почему :not()
селектор работает в jQuery, но не работает в CSS? Разве он не должен работать одинаково в обоих местах, так как jQuery утверждает, что он "CSS3-совместимый", или я что-то упускаю?
Есть ли чистый обходной путь CSS для этого, или мне придется полагаться на сценарий?
1 ответ
Почему
:not()
селектор работает в jQuery, но не работает в CSS? Разве он не должен работать одинаково в обоих местах, так как jQuery утверждает, что он "CSS3-совместимый", или я что-то упускаю?
Возможно, так и должно быть, но оказывается, что это не так: jQuery расширяет :not()
селектор, так что вы можете передать ему любой селектор, независимо от того, насколько сложным он может быть, и я подозреваю, что основной причиной этого является паритет с .not()
метод, который также принимает любой произвольно сложный селектор и фильтрует соответственно. В некотором смысле он поддерживает CSS-подобный синтаксис, но он выходит за рамки того, что определено в стандарте.
В качестве другого примера, это работает просто отлично (я знаю, что это невероятно нелепый пример по сравнению с тем, что приведено в вопросе, но это только для иллюстративных целей):
/*
* Select any section
* that's neither a child of body with a class
* nor a child of body having a descendant with a class.
*/
$('section:not(body > [class], body > :has([class]))')
Предварительный просмотр jsFiddle
Помните, что передача списка селекторов через запятую :not()
означает фильтрующие элементы, которые не соответствуют ни одному из перечисленных селекторов.
Теперь :not()
С другой стороны, псевдокласс в Селекторном уровне 3 очень ограничен. Вы можете передать только один простой селектор в качестве аргумента :not()
, Это означает, что вы можете передать только один из них одновременно:
- Универсальный селектор (
*
), опционально с пространством имен - Тип селектора (
a
,div
,span
,ul
,li
и т. д.), необязательно с пространством имен - Селектор атрибутов (
[att]
,[att=val]
и т. д.), необязательно с пространством имен - Выбор класса (
.class
) - Селектор идентификаторов (
#id
) - Псевдокласс (
:pseudo-class
)
Итак, вот различия между jQuery :not()
селектор и текущий стандарт :not()
селектор:
Прежде всего, чтобы ответить непосредственно на вопрос: вы не можете передать список селекторов через запятую. 1 Например, хотя данный селектор работает в jQuery, как показано в скрипте, он не является допустимым CSS:
/* If it's not in the Α, Β or Γ sectors, it's unassigned */ #sectors > div:not(.alpha, .beta, .gamma)
Есть ли чистый обходной путь CSS для этого, или мне придется полагаться на сценарий?
К счастью, в этом случае есть. Вы просто должны объединить несколько
:not()
селекторы, один за другим, чтобы сделать его действительным CSS:#sectors > div:not(.alpha):not(.beta):not(.gamma)
Это не делает селектор намного дольше, но несоответствие и неудобство остаются очевидными.
Вы не можете комбинировать простые селекторы в составные селекторы для использования с
:not()
, Это работает в jQuery, но является недопустимым CSS:/* Do not find divs that have all three classes together */ #foo > div:not(.foo.bar.baz)
Вам нужно будет разделить его на несколько отрицаний (а не просто соединить их!), Чтобы сделать его действительным CSS:
#foo > div:not(.foo), #foo > div:not(.bar), #foo > div:not(.baz)
Как видите, это еще более неудобно, чем пункт 1.
Вы не можете использовать комбинаторы. Это работает в jQuery, но не в CSS:
/* * Grab everything that is neither #foo itself nor within #foo. * Notice the descendant combinator (the space) between #foo and *. */ :not(#foo, #foo *)
Это особенно неприятный случай, прежде всего потому, что у него нет правильного обходного пути. Есть некоторые свободные обходные пути ( 1 и 2), но они почти всегда зависят от структуры HTML и поэтому очень ограничены в полезности.
В браузере, который реализует
querySelectorAll()
и:not()
селектор, используя:not()
в строке селектора таким способом, который делает его действительным селектором CSS, метод будет возвращать результаты напрямую, вместо того, чтобы возвращаться к Sizzle (механизм выбора jQuery, который реализует:not()
расширение). Если вы приверженец производительности, это положительный крошечный бонус, который вы обязательно слюните.
Хорошей новостью является то, что Selectors 4 усиливает :not()
селектор, чтобы разрешить разделенный запятыми список сложных селекторов. Сложный селектор - это либо простой одиночный, либо составной селектор, либо целая цепочка составных селекторов, разделенных комбинаторами. Одним словом, все, что вы видите выше.
Это означает, что приведенные выше примеры jQuery станут действительными селекторами уровня 4, что сделает псевдокласс намного, намного более полезным, когда реализации CSS начнут его поддерживать в ближайшие годы.
1 Хотя в этой статье говорится, что вы можете передать список селекторов через запятую :not()
в Firefox 3 вы не должны этого делать. Если он работает в Firefox 3, как утверждается в этой статье, то это из-за ошибки в Firefox 3, для которой я больше не могу найти билет, но он не должен работать, пока будущие браузеры не реализуют будущие стандарты. Видя, как часто эта статья цитируется на сегодняшний день, я оставил комментарий на этот счет, но, видя также, сколько лет статье и как редко обновляется сайт, я действительно не рассчитываю на то, что автор вернется, чтобы исправить Это.