为什么我的jQuery:not()选择器不在CSS中工作?

Bol*_*ock 57 css jquery css-selectors css3 jquery-selectors

我有这个布局:

<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>
Run Code Online (Sandbox Code Playgroud)

使用这些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; }
Run Code Online (Sandbox Code Playgroud)

我使用jQuery将unassigned类添加到没有其中一个类的扇区alpha,beta或者gamma:

$('#sectors > div:not(.alpha, .beta, .gamma)').addClass('unassigned');
Run Code Online (Sandbox Code Playgroud)

然后我对该类应用了一些不同的规则:

#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;
}
Run Code Online (Sandbox Code Playgroud)

在现代浏览器中,一切都完美无瑕.

交互式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;
}
Run Code Online (Sandbox Code Playgroud)

但是,一旦我这样做,它就会停止工作 - 在所有浏览器中!我的未指定扇区不会变灰,淡出或标记为"未分配".

更新但不是那么互动的jsFiddle预览

为什么:not()选择器在jQuery中工作但在CSS中失败?它不应该在两个地方都相同,因为jQuery声称是"CSS3兼容",或者是否有一些我缺少的东西?

是否有纯粹的CSS解决方法或我是否必须依赖脚本?

Bol*_*ock 79

为什么: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]))')
Run Code Online (Sandbox Code Playgroud)

jsFiddle预览

请记住,将逗号分隔的选择器列表传递给:not()意味着过滤与任何列出的选择器都不匹配的元素.

另一方面,:not()选择器级别3中伪类本身非常有限.您只能将一个简单的选择器作为参数传递给:not().这意味着您一次只能传递其中任何一个:

  • 通用选择器(*),可选择带有命名空间
  • 型选择器(a,div,span,ul,li,等),任选地与一个命名空间
  • 属性选择器([att],[att=val]等),可选地带有命名空间
  • 类选择器(.class)
  • ID选择器(#id)
  • 伪类(:pseudo-class)

所以,这里是jQuery的:not()选择器当前标准的:not()选择器之间的区别:

  1. 首先,直接回答问题:您不能传递逗号分隔的选择器列表.1例如,虽然给定的选择器在jQuery中工作,如小提琴中所示,但它不是有效的CSS:

    /* If it's not in the ?, ? or ? sectors, it's unassigned */
    #sectors > div:not(.alpha, .beta, .gamma)
    
    Run Code Online (Sandbox Code Playgroud)

    是否有纯粹的CSS解决方法或我是否必须依赖脚本?

    值得庆幸的是,在这种情况下,有.您只需要:not()一个接一个地链接多个选择器,以使其成为有效的CSS:

    #sectors > div:not(.alpha):not(.beta):not(.gamma)
    
    Run Code Online (Sandbox Code Playgroud)

    它不会使选择的是更长的时间,但矛盾和不便依然明显.

    更新了交互式jsFiddle预览

  2. 您不能将简单选择器组合到复合选择器中使用:not().这适用于jQuery,但是CSS无效:

    /* Do not find divs that have all three classes together */
    #foo > div:not(.foo.bar.baz)
    
    Run Code Online (Sandbox Code Playgroud)

    你需要把它分成多个否定(不只是链接它们!)来使它成为有效的CSS:

    #foo > div:not(.foo), #foo > div:not(.bar), #foo > div:not(.baz)
    
    Run Code Online (Sandbox Code Playgroud)

    如您所见,这比第1点更不方便.

  3. 你不能使用组合器.这适用于jQuery,但不适用于CSS:

    /* 
     * Grab everything that is neither #foo itself nor within #foo.
     * Notice the descendant combinator (the space) between #foo and *.
     */
    :not(#foo, #foo *)
    
    Run Code Online (Sandbox Code Playgroud)

    这是一个特别令人讨厌的案例,主要是因为它没有适当的解决方法.有一些松散的变通方法(12),但它们几乎总是依赖于HTML结构,因此在实用性方面非常有限.

  4. 在实现querySelectorAll():not()选择器的浏览器中,:not()在选择器字符串中使用使其成为有效CSS选择器的方式将导致该方法直接返回结果,而不是回退到Sizzle(jQuery的实现:not()扩展的选择器引擎).如果你是表现的坚持者,这是一个非常小的奖励,你肯定会垂涎三尺.

好消息是Selectors 4增强了:not()选择器以允许以逗号分隔的复杂选择器列表.复合选择器既可以是单独的简单选择器,也可以是复合选择器,也可以是由组合器分隔的整个复合选择器链.简而言之,你在上面看到的一切.

这意味着上面的jQuery示例将成为有效的4级选择器,当CSS实现在未来几年开始支持时,这将使伪类更加有用.


1 尽管本文说您可以:not()在Firefox 3中传递以逗号分隔的选择器列表,但您不应该这样做.如果它在Firefox 3中可行,正如该文章所声称的那样,那是因为Firefox 3中的一个错误,我找不到它的故障了,但是在未来的浏览器实现未来的标准之前它不应该工作.看到这篇文章到目前为止被引用的频率,我已经对这个效果留下了评论,但是看看这篇文章有多久以及该网站的更新频率如何,我真的不指望作者回来修复它.

  • 那篇文章真的很烦人.它似乎完全由人们认为`:not(#foo,#foo*)`在CSS中起作用.好吧,也许jQuery支持它也与它有关. (3认同)