58

我有这个布局:

<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类添加到没有其他类之一的扇区alphabeta或者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 解决方法或者我必须依赖脚本?

4

1 回答 1

83

为什么: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()Selectors level 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)
    

    是否有一个纯 CSS 解决方法或者我必须依赖脚本?

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

    #sectors > div:not(.alpha):not(.beta):not(.gamma)
    

    它不会使选择器更长,但不一致和不便仍然很明显。

    更新了交互式 jsFiddle 预览

  2. 您不能将简单选择器组合成复合选择器以用于: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 点更不方便。

  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 *)
    

    这是一个特别糟糕的情况,主要是因为它没有适当的解决方法。有一些松散的解决方法(12),但它们几乎总是依赖于 HTML 结构,因此在实用性上非常有限。

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

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

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


1 尽管本文说您可以:not()在 Firefox 3 中传递一个以逗号分隔的选择器列表,但您不应该这样做。如果它像那篇文章声称的那样在 Firefox 3 中工作,那是因为 Firefox 3 中的一个错误,我再也找不到票了,但在未来的浏览器实现未来标准之前它不应该工作。看到这篇文章迄今为止被引用的频率,我对此发表了评论,但也看到这篇文章有多老以及网站更新的频率有多低,我真的不指望作者回来修复它。

于 2012-05-23T00:00:59.050 回答