Este é um problema muito comum que surge devido a um mal-entendido sobre como :nth-child()
e como :nth-of-type()
funcionam. Infelizmente, não há atualmente nenhuma solução baseada em seletor ainda porque Seletores não fornecem uma maneira de corresponder ao enésimo filho que corresponde a um seletor arbitrário com base em um padrão como número ímpar, número par ou qualquer an+b
onde a != 1
e b != 0
. Isso vai além de apenas seletores de classe, para atribuir seletores, negações e combinações mais complexas de seletores simples.
A :nth-child()
pseudo classe conta elementos entre todos os seus irmãos sob o mesmo pai. Ele não conta apenas os irmãos que correspondem ao resto do seletor. Da mesma forma, a :nth-of-type()
pseudo classe conta irmãos que compartilham o mesmo tipo de elemento, que se refere ao nome da tag em HTML, e não ao resto do seletor.
Isso também significa que se todos os filhos do mesmo pai são do mesmo tipo de elemento, por exemplo, no caso de um corpo de tabela cujos únicos filhos são tr
elementos ou um elemento de lista cujos únicos filhos são li
elementos, então :nth-child()
e :nth-of-type()
se comportarão de forma idêntica, ou seja, para cada valor de an+b
, :nth-child(an+b)
e :nth-of-type(an+b)
irá coincidir com o mesmo conjunto de elementos.
Na verdade, todos os seletores simples em um determinado seletor composto, incluindo pseudoclasses como :nth-child()
e :not()
, funcionam independentemente uns dos outros, em vez de olhar para o subconjunto de elementos que são correspondidos pelo resto do seletor.
Isso também implica que não há noção de ordem entre os seletores simples dentro de cada seletor composto individual 1 , o que significa, por exemplo, os dois seletores a seguir são equivalentes:
table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row
Traduzido para o inglês, ambos significam:
Selecione qualquer tr
elemento que corresponda a todas as seguintes condições independentes:
- é um filho de número ímpar de seu pai;
- tem a classe "linha"; e
- é um descendente de um
table
elemento que possui a classe "myClass".
(você notará meu uso de uma lista não ordenada aqui, apenas para esclarecer o ponto)
Como atualmente não existe uma solução CSS pura, você terá que usar um script para filtrar elementos e aplicar estilos ou nomes de classes extras de acordo. Por exemplo, o seguinte é uma solução alternativa comum usando jQuery (assumindo que haja apenas um grupo de linhas preenchido com tr
elementos na tabela):
$('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');
});
Com o CSS correspondente:
table.myClass tr.row.odd {
...
}
Se você estiver usando ferramentas de teste automatizadas, como Selenium ou processamento de HTML com ferramentas como lxml, muitas dessas ferramentas permitem XPath como alternativa:
//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]
Outras soluções usando tecnologias diferentes são deixadas como um exercício para o leitor; este é apenas um exemplo breve e planejado para ilustração.
Pelo que vale a pena, há uma proposta de extensão da :nth-child()
notação a ser adicionada aos Seletores de nível 4 com o propósito específico de selecionar cada enésimo filho que corresponda a um determinado seletor.2
O seletor pelo qual filtrar correspondências é fornecido como um argumento :nth-child()
, novamente devido à forma como os seletores operam independentemente um do outro em uma sequência, conforme ditado pela sintaxe do seletor existente. Portanto, no seu caso, seria assim:
table.myClass tr:nth-child(odd of .row)
(Um leitor astuto notará imediatamente que deveria ser assim :nth-child(odd of tr.row)
, uma vez que os seletores simples tr
e :nth-child()
operam independentemente uns dos outros também. Este é um dos problemas com pseudo classes funcionais que aceitam seletores, uma lata de vermes que eu em vez de não abrir no meio desta resposta. Em vez disso, partirei do pressuposto de que a maioria dos sites não terá nenhum outro elemento além de tr
elementos como irmãos um do outro no corpo de uma tabela, o que tornaria qualquer uma das opções funcionalmente equivalente.)
Obviamente, sendo uma proposta totalmente nova em uma especificação totalmente nova, isso provavelmente não terá implementação até alguns anos depois. Nesse ínterim, você terá que continuar usando um script, como acima.
1 Se você especificar um tipo ou seletor universal, ele deve vir primeiro. Isso não muda a maneira como os seletores funcionam fundamentalmente; não é nada mais do que uma peculiaridade sintática.
2 Isso foi originalmente proposto porque :nth-match()
, no entanto, porque ainda conta um elemento relativo apenas a seus irmãos, e não a todos os outros elementos que correspondem ao seletor fornecido, desde 2014 foi reaproveitado como uma extensão do existente :nth-child()
.