¿Puedo combinar: nth-child () o: nth-of-type () con un selector arbitrario?

117

¿Hay alguna forma de seleccionar cada enésimo niño que coincida (o no) con un selector arbitrario ? Por ejemplo, quiero seleccionar todas las filas impares de la tabla, pero dentro de un subconjunto de filas:

table.myClass tr.row:nth-child(odd) {
  ...
}
<table class="myClass">
  <tr>
    <td>Row
  <tr class="row"> <!-- I want this -->
    <td>Row
  <tr class="row">
    <td>Row
  <tr class="row"> <!-- And this -->
    <td>Row
</table>

Pero :nth-child()sólo parece contar todos los trelementos, independientemente de si están o no de la clase "fila", por lo que termino con el que incluso elemento de "fila" en lugar de los dos que estoy buscando. Lo mismo sucede con :nth-of-type().

¿Alguien puede explicar por qué?

atanamir
fuente

Respuestas:

144

Este es un problema muy común que surge debido a una mala comprensión de cómo :nth-child()y :nth-of-type()funcionan. Desafortunadamente, actualmente no existe una solución basada en selectores porque Selectors no proporciona una forma de hacer coincidir el enésimo hijo que coincide con un selector arbitrario basado en un patrón como número impar, número par o cualquier an+blugar a != 1y b != 0. Esto se extiende más allá de los selectores de clases, a los selectores de atributos, negaciones y combinaciones más complejas de selectores simples.

La :nth-child()pseudoclase cuenta elementos entre todos sus hermanos bajo el mismo padre. No cuenta solo los hermanos que coinciden con el resto del selector. De manera similar, la :nth-of-type()pseudoclase cuenta a los hermanos que comparten el mismo tipo de elemento, que se refiere al nombre de la etiqueta en HTML, y no al resto del selector.

Esto también significa que si todos los hijos del mismo padre son del mismo tipo de elemento, por ejemplo, en el caso de un cuerpo de tabla cuyos únicos hijos son trelementos o un elemento de lista cuyos únicos hijos son lielementos, entonces :nth-child()y :nth-of-type()se comportará de manera idéntica, es decir para cada valor de an+b, :nth-child(an+b)y :nth-of-type(an+b)coincidirá con el mismo conjunto de elementos.

De hecho, todos los selectores simples en un selector compuesto dado, incluidas las pseudoclases como :nth-child()y :not(), funcionan de forma independiente entre sí, en lugar de mirar el subconjunto de elementos que coinciden con el resto del selector.

Esto también implica que no existe una noción de orden entre selectores simples dentro de cada selector compuesto individual 1 , lo que significa, por ejemplo, que los dos selectores siguientes son equivalentes:

table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row

Traducido al inglés, ambos significan:

Seleccione cualquier trelemento que cumpla con todas las siguientes condiciones independientes:

  • es un hijo impar de su padre;
  • tiene la clase "fila"; y
  • es un descendiente de un tableelemento que tiene la clase "myClass".

(notará mi uso de una lista desordenada aquí, solo para llevar el punto a casa)

Debido a que actualmente no existe una solución CSS pura, tendrá que usar un script para filtrar elementos y aplicar estilos o nombres de clases adicionales en consecuencia. Por ejemplo, la siguiente es una solución alternativa común con jQuery (asumiendo que solo hay un grupo de filas poblado con trelementos dentro de la tabla):

$('table.myClass').each(function() {
  // Note that, confusingly, jQuery's filter pseudos are 0-indexed
  // while CSS :nth-child() is 1-indexed
  $('tr.row:even').addClass('odd');
});

Con el CSS correspondiente:

table.myClass tr.row.odd {
  ...
}

Si está utilizando herramientas de prueba automatizadas como Selenium o procesando HTML con herramientas como lxml, muchas de estas herramientas permiten XPath como alternativa:

//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]

Otras soluciones que utilizan diferentes tecnologías se dejan como ejercicio para el lector; este es solo un ejemplo breve y artificial a modo de ilustración.


Por lo que vale, existe una propuesta para agregar una extensión a la :nth-child()notación al nivel 4 de Selectores con el propósito específico de seleccionar cada enésimo hijo que coincida con un selector dado. 2

El selector por el cual filtrar coincidencias se proporciona como un argumento :nth-child(), nuevamente debido a cómo los selectores operan de forma independiente entre sí en una secuencia según lo dicta la sintaxis del selector existente. Entonces, en su caso, se vería así:

table.myClass tr:nth-child(odd of .row)

(Un lector astuto notará de inmediato que esto debería ser así :nth-child(odd of tr.row), ya que los selectores simples try también :nth-child()operan independientemente unos de otros. Este es uno de los problemas con las pseudoclases funcionales que aceptan selectores, una lata de gusanos que prefiero no abrir en el medio de esta respuesta. En su lugar, voy a asumir que la mayoría de los sitios no tendrán ningún otro elemento que no sean trelementos como hermanos entre sí en el cuerpo de una tabla, lo que haría que cualquiera de las opciones sea funcionalmente equivalente).

Por supuesto, al ser una propuesta completamente nueva con una especificación completamente nueva, esto probablemente no verá implementación hasta dentro de unos años. Mientras tanto, tendrá que seguir usando un script, como se indicó anteriormente.


1 Si especifica un tipo o selector universal, debe ir primero. Sin embargo, esto no cambia el funcionamiento fundamental de los selectores; no es más que un capricho sintáctico.

2 Esto se propuso originalmente porque :nth-match(), sin embargo, debido a que todavía cuenta un elemento en relación solo con sus hermanos, y no con todos los demás elementos que coinciden con el selector dado, desde 2014 se ha reutilizado como una extensión del existente :nth-child().

BoltClock
fuente
3
"(Notarás mi uso de una lista desordenada aquí, solo para enfatizar el punto)" Me gustaría que más personas fueran tan deliberadas sobre el uso de balas ordenadas vs desordenadas. Gracias por su respuesta.
The Red Pea
1
@The Red Pea: Una de las cosas que más me molestan en HTML: "En orden de mayor / menor a menor / mayor:" seguido de una lista desordenada. Quiero decir, vamos, ¿en serio?
BoltClock
6

Realmente no..

cita de los documentos

La :nth-childpseudoclase coincide con un elemento que tiene un hermano + b-1 antes en el árbol del documento , para un valor positivo o cero dado para n, y tiene un elemento padre.

Es un selector propio y no se combina con clases. En su regla, solo tiene que satisfacer ambos selectores al mismo tiempo, por lo que mostrará las :nth-child(even)filas de la tabla si también tienen el.row clase.

Gabriele Petrioli
fuente
0

nth-of-typefunciona de acuerdo con el índice del mismo tipo de elemento, pero nth-childfunciona solo de acuerdo con el índice, sin importar qué tipo de elementos hermanos sean.

Por ejemplo

<div class="one">...</div>
<div class="two">...</div>
<div class="three">...</div>
<div class="four">...</div>
<div class="five">...</div>
<div class="rest">...</div>
<div class="rest">...</div>
<div class="rest">...</div>
<div class="rest">...</div>
<div class="rest">...</div>

Supongamos que en el html anterior queremos ocultar todos los elementos que tienen la clase de descanso.

En este caso nth-child, y nth-of-typefuncionará exactamente igual que todos los elementos son del mismo tipo que es <div>por lo que debe ser css

.rest:nth-child(6), .rest:nth-child(7), .rest:nth-child(8), .rest:nth-child(9), .rest:nth-child(10){
    display:none;
}

O

.rest:nth-of-type(6), .rest:nth-of-type(7), .rest:nth-of-type(8), .rest:nth-of-type(9), .rest:nth-of-type(10){
    display:none;
}

Ahora debes preguntarte cuál es la diferencia entre nth-childy nth-of-typeentonces esta es la diferencia

Suponga que el html es

<div class="one">...</div>
<div class="two">...</div>
<div class="three">...</div>
<div class="four">...</div>
<div class="five">...</div>
<p class="rest">...</p>
<p class="rest">...</p>
<p class="rest">...</p>
<p class="rest">...</p>
<p class="rest">...</p>

En el html anterior el tipo de .restelemento es diferente a otros .restson párrafos y otros son div así que en este caso si lo usas nth-childtienes que escribir así

.rest:nth-child(6), .rest:nth-child(7), .rest:nth-child(8), .rest:nth-child(9), .rest:nth-child(10){
    display:none;
}

pero si usa nth-of-type css puede ser esto

.rest:nth-of-type(1), .rest:nth-of-type(2), .rest:nth-of-type(3), .rest:nth-of-type(4), .rest:nth-of-type(5){
    display:none;
}

Como el tipo de .restelemento es, <p>aquí nth-of-typeestá detectando el tipo de .resty luego aplicó css en el 1er, 2do, 3er, 4to, 5to elemento de <p>.

Gaurav Aggarwal
fuente
¿Qué utilidad tiene eso para las <tr>etiquetas?
Alexis Wilke
0

Es posible que pueda hacer eso con xpath. algo como //tr[contains(@class, 'row') and position() mod 2 = 0]podría funcionar. Hay otras preguntas de SO que amplían los detalles sobre cómo hacer coincidir las clases con mayor precisión.

the8472
fuente
0

Aqui esta tu respuesta

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>TEST</title>

  <style>

    .block {
      background: #fc0;
      margin-bottom: 10px;
      padding: 10px;
    }
    /* .large > .large-item:nth-of-type(n+5) {
      background: #f00;
    } */

    .large-item ~ .large-item ~ .large-item ~ .large-item ~ .large-item {
      background: #f00;
    }

  </style>
</head>
<body>

<h1>Should be the 6th Hello Block that start red</h1>
<div class="small large">
  <div class="block small-item">Hello block 1</div>
  <div class="block small-item large-item">Hello block 2</div>
  <div class="block small-item large-item">Hello block 3</div>
  <div class="block small-item large-item">Hello block 4</div>
  <div class="block small-item large-item">Hello block 5</div>
  <div class="block small-item large-item">Hello block 6</div>
  <div class="block small-item large-item">Hello block 7</div>
  <div class="block small-item large-item">Hello block 8</div>
</div>

</body>
</html>
Pocketninja
fuente
0

Todas las preguntas sobre el uso de nth-child y omitir etiquetas ocultas parecen estar redirigiendo como engaños de esta, así que dejaré esto aquí. Encontré este blog https://blog.blackbam.at/2015/04/09/css-nth-child-selector-ignore-hidden-element/ que usa un enfoque inteligente de CSS para hacer que nth-child ignore los elementos ocultos, como sigue:

El siguiente CSS agrega un margen derecho a cada segundo elemento visible sin importar qué elemento tenga la clase cpw.

.cpw {
    display:none;
}

.video_prewrap {
    margin-right:20px;
}

.video_prewrap:nth-child(2n) {
    margin-right:0;
}

.cpw ~ .video_prewrap:nth-child(2n) {
    margin-right:20px;
}

.cpw ~ .video_prewrap:nth-child(2n-1) {
    margin-right:0;
}

¡Espero que ayude a alguien que está siguiendo el rastro de los incautos para ignorar las preguntas de elementos ocultos!

IrishDubGuy
fuente
1
Me gustaría votar esto, pero necesita una demostración funcional.
Moob
Lo que recuerdo es que esto no fue tan sólido como parecía inicialmente; ahora iría con el comentario más votado, esto no es posible.
IrishDubGuy
0

SI tiene la misma clase principal para todos los selectores, entonces usa esa clase document.querySelector("main .box-value:nth-child(3) select.priorityOption"); porque en ese caso document.querySelector("main .box-value select.priorityOption:nth-child(3)");no funciona. Gracias

<div class="card table">
    <div class="box">
        <div class="box-value">
            <select class="priorityOption">
                <option value="">--</option>
                <option value="">LOREM</option>
                <option value="">LOREM</option>
            </select>
        </div>

        <div class="box-value">
            <select class="priorityOption">
                <option value="">--</option>
                <option value="">LOREM</option>
                <option value="">LOREM</option>
            </select>
        </div>

        <div class="box-value">
            <select class="priorityOption">
                <option value="">--</option>
                <option value="">LOREM</option>
                <option value="">LOREM</option>
            </select>
        </div>
    </div>
</div>
Jatin Aggarwal
fuente