¿Por qué mi selector jQuery :not() no funciona en CSS?

Resuelto BoltClock asked hace 12 años • 1 respuestas

Tengo este diseño:

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

Con estas reglas 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; }

Utilizo jQuery para agregar la unassignedclase a sectores que de otro modo no tendrían una de las clases alpha, betao gamma:

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

Luego aplico algunas reglas diferentes a esa clase:

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

Y todo funciona perfectamente en los navegadores modernos.

Vista previa interactiva de jsFiddle

Pero dado que el :not()selector en jQuery se basa :not()en CSS3 , estaba pensando que podría moverlo directamente a mi hoja de estilo para no tener que depender de agregar una clase adicional usando jQuery. Además, no estoy realmente interesado en admitir versiones anteriores de IE y otros navegadores tienen un excelente soporte para el :not()selector.

Así que intento cambiar la .unassignedparte anterior a esto (sabiendo que solo tendré los sectores Α, Β y Γ en mi diseño):

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

Pero tan pronto como hago esto, deja de funcionar, ¡en todos los navegadores ! Mis sectores no asignados ya no aparecen atenuados, descoloridos ni etiquetados como "No asignados".

Vista previa de jsFiddle actualizada pero no tan interactiva

¿Por qué el :not()selector funciona en jQuery pero falla en CSS? ¿No debería funcionar de manera idéntica en ambos lugares ya que jQuery afirma ser "compatible con CSS3", o me falta algo?

¿Existe una solución CSS pura para esto o tendré que confiar en un script?

BoltClock avatar May 23 '12 07:05 BoltClock
Aceptado

¿Por qué el :not()selector funciona en jQuery pero falla en CSS? ¿No debería funcionar de manera idéntica en ambos lugares ya que jQuery afirma ser "compatible con CSS3", o me falta algo?

Quizás debería , pero resulta que no es así : jQuery extiende el :not()selector de tal manera que puedes pasarle cualquier selector , sin importar cuán complejo pueda ser, y sospecho que la razón principal de esto es la paridad con el .not()método , que también toma cualquier selector arbitrariamente complejo y filtra en consecuencia. De alguna manera mantiene una sintaxis similar a CSS, pero se extiende desde lo que está definido en el estándar.

Como otro ejemplo, esto funciona bien (sé que es un ejemplo increíblemente ridículo en comparación con lo que se da en la pregunta, pero es solo para fines ilustrativos):

/* 
 * 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]))')

Vista previa de jsFiddle

Recuerde que pasar una lista de selectores separados por comas :not()significa filtrar elementos que no coinciden con ninguno de los selectores enumerados .

Ahora bien, la :not()pseudoclase en Selectores nivel 3 , por otro lado, está muy limitada en sí misma. Sólo puedes pasar un único selector simple como argumento a :not(). Esto significa que sólo puedes aprobar cualquiera de estos a la vez:

  • Selector universal ( *), opcionalmente con un espacio de nombres.
  • Selector de tipo ( ,,,,,, aetc. ) , opcionalmente con un espacio de nombresdiv .spanulli
  • Selector de atributos ( [att],, [att=val]etc.), opcionalmente con un espacio de nombres.
  • Selector de clase ( .class)
  • selector de identificación ( #id)
  • Pseudoclase ( :pseudo-class)

Entonces, aquí están las diferencias entre el selector de jQuery:not() y el selector del estándar actual:not() :

  1. En primer lugar, para responder la pregunta directamente: no se puede pasar una lista de selección separada por comas. 1 Por ejemplo, si bien el selector dado funciona en jQuery como se muestra en el violín, no es CSS válido:

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

    ¿Existe una solución CSS pura para esto o tendré que confiar en un script?

    Afortunadamente, en este caso lo hay. Simplemente tienes que encadenar múltiples :not()selectores, uno tras otro, para que sea CSS válido:

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

    No hace que el selector sea mucho más largo, pero la inconsistencia y los inconvenientes siguen siendo evidentes.

    Vista previa interactiva actualizada de jsFiddle

  2. No puede combinar selectores simples en selectores compuestos para usarlos con :not(). Esto funciona en jQuery, pero no es CSS válido:

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

    Tendrás que dividirlo en múltiples negaciones (¡no solo encadenarlas!) para que sea CSS válido:

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

    Como puede ver, esto es incluso más inconveniente que el punto 1.

  3. No puedes usar combinadores. Esto funciona en jQuery, pero no en CSS:

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

    Este es un caso particularmente desagradable, principalmente porque no existe una solución alternativa adecuada. Existen algunas soluciones alternativas ( 1 y 2 ), pero casi siempre dependen de la estructura HTML y, por lo tanto, su utilidad es muy limitada.

  4. En un navegador que implementa querySelectorAll()y el :not()selector, usar :not()una cadena de selector de una manera que la convierta en un selector CSS válido hará que el método devuelva resultados directamente, en lugar de recurrir a Sizzle (el motor de selección de jQuery que implementa la :not()extensión). Si eres un riguroso con el rendimiento, este es un bono positivamente minúsculo que definitivamente te hará salivar.

La buena noticia es que Selectors 4 mejora el :not()selector para permitir una lista de selectores complejos separados por comas. Un selector complejo es simplemente un selector simple o compuesto, o una cadena completa de selectores compuestos separados por combinadores. En definitiva, todo lo que ves arriba.

Esto significa que los ejemplos de jQuery anteriores se convertirán en selectores válidos de nivel 4, lo que hará que la pseudoclase sea mucho, mucho más útil cuando las implementaciones de CSS comiencen a admitirla en los próximos años.


1 Aunque este artículo dice que puedes pasar una lista de selectores separados por comas :not()en Firefox 3, se supone que no deberías poder hacerlo. Si funciona en Firefox 3 como dice el artículo, entonces se debe a un error en Firefox 3 para el cual ya no puedo encontrar el ticket, pero no debería funcionar hasta que los futuros navegadores implementen estándares futuros. Al ver la frecuencia con la que se cita ese artículo hasta la fecha, dejé un comentario en este sentido, pero al ver también la antigüedad del artículo y la poca frecuencia con la que se actualiza el sitio, realmente no cuento con que el autor regrese para arreglarlo. él.

BoltClock avatar May 23 '2012 00:05 BoltClock