css - has - ¿Puedo combinar: nth-child() o: nth-of-type() con un selector arbitrario?
css selectores (4)
¿Hay alguna forma de seleccionar cada enésimo hijo que coincida (o no coincida) con un selector arbitrario ? Por ejemplo, quiero seleccionar cada fila de tabla impar, pero dentro de un subconjunto de las 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()
solo parece contar todos los elementos tr
sin importar si son de la clase "fila", así que termino con el elemento "row" incluso en lugar de los dos que estoy buscando para. Lo mismo sucede con :nth-of-type()
.
¿Alguien puede explicar por qué?
Es posible que puedas 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 de forma más precisa.
Este es un problema muy común que surge debido a un malentendido de cómo :nth-child()
y :nth-of-type()
funcionan. Desafortunadamente, actualmente no existe una solución basada en selectores porque Selectores no proporciona una forma de coincidir con el enésimo hijo que coincide con un selector arbitrario basado en un patrón como impar, numerado par o cualquier an+b
donde a != 1
y b != 0
. Esto se extiende más allá de los selectores de clase, para atribuir selectores, negaciones y combinaciones más complejas de selectores simples.
La :nth-child()
cuenta elementos entre todos sus hermanos bajo el mismo padre. No cuenta solo los hermanos que coinciden con el resto del selector. Del mismo modo, la :nth-of-type()
cuenta 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 elementos tr
o un elemento de lista cuyos únicos hijos son elementos li
, entonces :nth-child()
y :nth-of-type()
se comportará de forma 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, incluyendo pseudo-clases tales como :nth-child()
y :not()
, trabajan independientemente el uno del otro, en lugar de mirar el subconjunto de elementos que se corresponden con el resto del selector.
Esto también implica que no hay ninguna noción de orden entre selectores simples dentro de cada selector compuesto individual 1 , lo que significa, por ejemplo, que los siguientes dos selectores son equivalentes:
table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row
Traducido al inglés, ambos significan:
Seleccione cualquier elemento
tr
que coincida con todas las siguientes condiciones independientes:
- es un hijo impar de su padre;
- tiene la clase "fila"; y
- es un descendiente de un elemento de
table
que tiene la clase "myClass".
(Notarás mi uso de una lista desordenada aquí, solo para llevar el punto a casa)
Debido a que actualmente no hay una solución pura de CSS, deberá usar una secuencia de comandos para filtrar elementos y aplicar estilos o nombres de clases adicionales en consecuencia. Por ejemplo, la siguiente es una solución común usando jQuery (suponiendo que solo haya un grupo de filas poblado con elementos tr
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 usa herramientas de prueba automatizadas como Selenium o procesa 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 usan diferentes tecnologías se dejan como un ejercicio para el lector; esto es solo un ejemplo breve y artificial para la ilustración.
Por lo que vale, hay una propuesta para que se agregue una notación :nth-child()
al nivel 4 de Selectores con el propósito específico de seleccionar cada n-ésimo niño que coincida con un selector dado. 2
El selector por el cual filtrar coincidencias se proporciona como un argumento para :nth-child()
, de nuevo debido a cómo los selectores operan independientemente el uno del otro en una secuencia según lo dictado por la sintaxis del selector existente. Entonces en tu caso, se vería así:
table.myClass tr:nth-child(odd of .row)
(Un lector astuto notará de inmediato que esto debería ser :nth-child(odd of tr.row)
lugar, ya que los simples selectores tr
y :nth-child()
operan independientemente el uno del otro también. Este es uno de los problemas con las pseudo-clases funcionales que aceptan selectores, una lata de gusanos que prefiero no abrir en el medio de esta respuesta. En cambio, voy a ir con la suposición de que la mayoría de los sitios no tendrán otros elementos que los elementos tr
como hermanos el uno del otro en un cuerpo de tabla, lo que haría que cualquiera de las opciones sea funcionalmente equivalente).
Por supuesto, al tratarse de una nueva propuesta en una nueva especificación, probablemente no se implementará hasta dentro de unos años. Mientras tanto, tendrás que seguir usando un script, como se indica arriba.
1 Si especifica un tipo o selector universal, debe ser lo primero. Sin embargo, esto no cambia la forma en que funcionan los selectores; no es más que una peculiaridad sintáctica.
2 Esto se propuso originalmente como :nth-match()
, sin embargo, debido a que todavía cuenta un elemento relativo solo a sus hermanos, y no a todos los demás elementos que coinciden con el selector dado, desde entonces se reutilizó como una extensión de el existente :nth-child()
lugar.
Realmente no..
La
:nth-child
coincide con un elemento que tiene un + b-1 hermanos antes que él en el árbol de documentos , para un valor positivo o cero dado para n, y tiene un elemento principal.
Es un selector propio y no se combina con las clases. En su regla solo tiene que satisfacer a ambos selectores al mismo tiempo, de modo que mostrará las filas de la tabla :nth-child(even)
si también tienen la clase .row
.
nth-of-type
funciona de acuerdo con el índice del mismo tipo del elemento pero nth-child
solo funciona de acuerdo con el índice sin importar qué tipo de hermanos sean los elementos.
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 html anterior queremos ocultar todos los elementos que tienen clase de descanso.
En este caso, nth-child
y nth-of-type
funcionarán exactamente igual que todos los elementos del mismo tipo que es <div>
así que css debería ser
.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 debe estarse preguntando cuál es la diferencia entre nth-child
y nth-of-type
así que esta es la diferencia
Supongamos 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 elemento .rest
es diferente de los demás .rest
son párrafos y otros son div, por lo que en este caso, si usas nth-child
tienes 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 usas css de tipo nth 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 elemento
.rest
es<p>
así que aquínth-of-type
está detectando el tipo de.rest
y luego aplicó css en el primer, segundo, tercer, cuarto, quinto elemento de<p>
.