57 votes

Pourquoi mon sélecteur jQuery: not () ne fonctionne-t-il pas en CSS?

J'ai ce modèle:

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

Avec ces règles 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; }

J'utilise jQuery pour ajouter l' unassigned classe pour les secteurs qui ne sont pas autrement l'une des classes d' alpha, beta ou gamma:

$('#sectors > div:not(.alpha, .beta, .gamma)').addClass('unassigned');

Ensuite, j'applique quelques règles différentes à cette classe:

#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;
}

Et tout fonctionne parfaitement dans les navigateurs modernes.

Interactive jsFiddle aperçu

Mais, voyant que l' :not() sélecteur jQuery est basé sur :not() en CSS3, je pensais que je pouvais passer directement dans ma feuille de style, donc je n'aurais pas à compter sur l'ajout d'une classe supplémentaire à l'aide de jQuery. D'ailleurs, je ne suis pas vraiment intéressée à soutenir les anciennes versions d'IE et d'autres navigateurs ont un excellent support pour l' :not() - sélecteur.

J'ai donc essayer de changer de .unassigned partie au-dessus de cela (sachant que je n'aurai que des secteurs Α, Β et Γ dans ma mise en page):

#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;
}

Mais dès que j'ai ce faire, il s'arrête de travailler dans tous les navigateurs! Mon non affecté secteurs ne sont pas grisé, disparu ou étiquetés "non affecté" plus.

Mise à jour, mais pas de manière interactive jsFiddle aperçu

Pourquoi ne l' :not() sélecteur de travail en jQuery, mais ne parviennent pas dans le CSS? Ne faut-il pas travailler de manière identique dans les deux lieux depuis jQuery emprunte à la norme CSS3, ou est-il quelque chose que je suis absent?

Est-il un pur CSS solution de contournement pour ce ou vais-je devoir compter sur un script?

79voto

BoltClock Points 249668

Pourquoi ne l' :not() sélecteur de travail en jQuery, mais ne parviennent pas dans le CSS? Ne faut-il pas travailler de manière identique dans les deux lieux depuis jQuery emprunte à la norme CSS3, ou est-il quelque chose que je suis absent?

Peut-être qu'il devrait, mais il s'avère qu'il n'est pas: jQuery étend l' :not() sélecteur de tels que vous pouvez passer toute sélecteur à elle, peu importe comment il est complexe, et je soupçonne que la raison principale de ceci est en faveur de la parité avec l' .not() méthode, qui prend également en tout arbitraire sélecteur complexe et filtres en conséquence. Il le fait de façon à maintenir un CSS syntaxe, mais elle s'étend à partir de ce qui est défini dans la norme.

Comme autre exemple, cela fonctionne bien (je sais que c'est incroyablement ridicule exemple par rapport à ce qui est donné dans la question, mais c'est juste pour illustrer):

/* 
 * 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 aperçu

Rappelez-vous que l'adoption d'une liste séparée par des virgules des sélecteurs :not() moyen du filtrage des éléments qui ne correspondent pas à la liste des sélecteurs.

Maintenant l' :not() pseudo-classe dans les Sélecteurs de niveau 3, d'autre part, est très limité par lui-même. Vous ne pouvez passer d'un simple sélecteur comme un argument à l' :not(). Cela signifie que vous pouvez passer qu'un à la fois:

  • Sélecteur universel (*), éventuellement avec un espace de noms

  • Sélecteur de Type (a, div, span, ul, li, etc), éventuellement avec un espace de noms

  • Sélecteur d'attributs ([att], [att=val], etc), éventuellement avec un espace de noms

  • Sélecteur de classe (.class)

  • Sélecteur d'ID (#id)

  • La Pseudo-classe (:pseudo-class)

Donc, voici les différences entre jQuery :not() sélecteur et CSS3 l' :not() selector:

  1. D'abord et avant tout, de répondre à la question directement: vous ne pouvez pas passer par une virgule liste de sélection.1 Par exemple, alors que le sélecteur de donnée fonctionne en jQuery, comme le montre le violon, il n'est pas valide CSS:

    /* If it's not in the Α, Β or Γ sectors, it's unassigned */
    #sectors > div:not(.alpha, .beta, .gamma)
    

    Est-il un pur CSS solution de contournement pour ce ou vais-je devoir compter sur un script?

    Heureusement, dans ce cas, il est. Il vous suffit de chaîne multiple, :not() sélecteurs, l'un après l'autre, afin de la rendre valide CSS:

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

    Il ne fait pas le sélecteur que beaucoup plus de temps, mais l'incohérence et les inconvénients restent évidentes.

    Mise à jour interactive jsFiddle aperçu

  2. Vous ne pouvez pas combiner les sélecteurs simples composés de sélecteurs pour une utilisation avec des :not(). Cela fonctionne en jQuery, mais n'est pas valide CSS:

    /* Do not find divs that have all three classes together */
    div:not(.foo.bar.baz)
    

    Vous aurez besoin de le diviser en plusieurs négations (et pas seulement de la chaîne d'eux!) pour la rendre valide CSS:

    div:not(.foo), div:not(.bar), div:not(.baz)
    

    Comme vous pouvez le voir, c'est encore plus gênant que le point 1.

  3. Vous ne pouvez pas utiliser les combinators. Cela fonctionne en jQuery, mais pas CSS:

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

    C'est un cas méchant, principalement parce qu'il n'a pas de véritable solution de contournement. Il y a quelques lâche solutions de contournement (1 et 2), mais ils dépendent généralement de la structure HTML et sont donc très limitée dans l'utilitaire.

  4. Dans un navigateur, qui implémente à la fois l' API de Sélecteurs (niveau 2) et de l' :not() sélecteur CSS3, à l'aide de :not() dans un sélecteur de chaîne dans une manière qui le rend un selecteur CSS valide va provoquer le sélecteur de chaîne pour renvoyer les résultats à l'aide de querySelectorAll() et/ou matches(), au lieu de retomber à Grésiller (jQuery sélecteur moteur qui implémente l' :not() extension). Si vous êtes anal sur la performance, c'est une façon positive de minuscules bonus, vous aurez certainement saliver.

Il est intéressant de noter que les Sélecteurs 4 spec améliore la :not() sélecteur pour permettre une liste séparée par des virgules composé de sélecteurs. Composé de sélecteurs sont, tout simplement, simple sélecteurs combiné (composées), sans combinators les séparant. Cela signifie que les sélecteurs jQuery indiquées dans les points 1 et 2 ci-dessus va probablement devenir l'équivalent, et valable au niveau 4 du sélecteur de bien, qui va faire de la pseudo-classe beaucoup, beaucoup plus utile lors de la CSS des analyseurs de commencer à le soutenir dans les années à venir.

Malheureusement, cela ne permet toujours pas combinators comme indiqué au point 3, au moins pas de cette écriture, de sorte que jQuery a encore de la nature de la haute main ici. Qui ne devrait pas être un problème si, de l'OMI, comme vous devriez le faire que rarement besoin d'utiliser combinators au sein de l' :not() selector (mais c'est juste mon prendre sur elle).2


1Bien que cet article dit que l'on peut passer d'une liste séparée par des virgules des sélecteurs :not() dans Firefox 3, vous n'êtes pas censé être en mesure de. Si cela fonctionne dans Firefox 3 que cet article prétend, alors c'est à cause d'un bug dans Firefox 3, pour lesquelles je ne peux pas trouver le billet, mais il ne devrait pas travailler jusqu'à ce que le futur mettre en œuvre les futures normes. Voir combien de fois que l'article est cité à ce jour, j'ai laissé un commentaire à cet effet, mais de voir aussi comment l'ancien article est et la maniere dont le site est en cours de mise à jour, je ne suis vraiment pas compter sur l'auteur de revenir à résoudre.

2d'autre part, je n'ai pas d'objections personnelles à l'aide de l' .not() méthode complexe, avec des sélecteurs et les combinators moi-même. Comme une question de fait, la documentation de jQuery :not() sélecteur de membres", L' .not() méthode sera à la fin de vous fournir plus lisible sélections de poussant complexe de sélecteurs, ou des variables dans un :not() sélecteur de filtre. Dans la plupart des cas, il est un meilleur choix."

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X