Questo è un problema molto comune che sorge a causa di un malinteso su come :nth-child()
e :nth-of-type()
lavorare. Sfortunatamente, al momento non esiste ancora una soluzione basata sul selettore perché Selectors non fornisce un modo per abbinare l'ennesimo figlio che corrisponde a un selettore arbitrario basato su un modello come numero dispari, numero pari o qualsiasi an+b
dove a != 1
e b != 0
. Questo va oltre i selettori di classe, per attribuire selettori, negazioni e combinazioni più complesse di selettori semplici.
La :nth-child()
pseudo-classe conta gli elementi tra tutti i loro fratelli sotto lo stesso genitore. Non conta solo i fratelli che corrispondono al resto del selettore. Allo stesso modo, la :nth-of-type()
pseudo-classe conta i fratelli che condividono lo stesso tipo di elemento, che si riferisce al nome del tag in HTML, e non il resto del selettore.
Ciò significa anche che se tutti i figli dello stesso genitore sono dello stesso tipo di elemento, ad esempio nel caso di un corpo di tabella i cui unici figli sono tr
elementi o un elemento di lista i cui unici figli sono li
elementi, allora :nth-child()
e :nth-of-type()
si comporterà in modo identico, cioè per ogni valore di an+b
, :nth-child(an+b)
e :nth-of-type(an+b)
corrisponderà lo stesso insieme di elementi.
In effetti, tutti i selettori semplici in un dato selettore composto, comprese le pseudo-classi come :nth-child()
e :not()
, funzionano indipendentemente l' una dall'altra, piuttosto che guardare il sottoinsieme di elementi che sono abbinati dal resto del selettore.
Ciò implica anche che non esiste una nozione di ordine tra selettori semplici all'interno di ogni singolo selettore composto 1 , il che significa ad esempio che i due selettori seguenti sono equivalenti:
table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row
Tradotti in inglese, significano entrambi:
Seleziona qualsiasi tr
elemento che soddisfi tutte le seguenti condizioni indipendenti:
- è un figlio dispari del suo genitore;
- ha la classe "riga"; e
- è un discendente di un
table
elemento che ha la classe "myClass".
(noterai il mio uso di un elenco non ordinato qui, solo per portare a casa il punto)
Poiché attualmente non esiste una soluzione CSS pura, dovrai utilizzare uno script per filtrare gli elementi e applicare di conseguenza stili o nomi di classi extra. Ad esempio, la seguente è una soluzione alternativa comune utilizzando jQuery (supponendo che ci sia un solo gruppo di righe popolato con tr
elementi all'interno della tabella):
$('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 il CSS corrispondente:
table.myClass tr.row.odd {
...
}
Se stai utilizzando strumenti di test automatizzati come Selenium o elaborando HTML con strumenti come lxml, molti di questi strumenti consentono XPath come alternativa:
//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]
Altre soluzioni che utilizzano tecnologie diverse sono lasciate come esercizio al lettore; questo è solo un breve esempio artificioso per l'illustrazione.
Per quel che vale, c'è una proposta per un'estensione della :nth-child()
notazione da aggiungere al livello 4 dei Selettori allo scopo specifico di selezionare ogni ennesimo bambino che corrisponde a un dato selettore. 2
Il selettore mediante il quale filtrare le corrispondenze viene fornito come argomento :nth-child()
, ancora una volta a causa del modo in cui i selettori operano indipendentemente l'uno dall'altro in una sequenza come dettata dalla sintassi del selettore esistente. Quindi nel tuo caso, sarebbe simile a questo:
table.myClass tr:nth-child(odd of .row)
(Un lettore attento avrà nota subito che questo dovrebbe essere :nth-child(odd of tr.row)
invece, poiché i selettori semplici tr
e :nth-child()
operano indipendentemente l'uno dall'altro come bene. Questo è uno dei problemi funzionali pseudo-classi che accettano selettori, una lattina di vermi avevo piuttosto non aprire nel mezzo di questa risposta. Invece presumo che la maggior parte dei siti non avrà altri elementi oltre agli tr
elementi come fratelli l'uno dell'altro in un corpo di tabella, il che renderebbe entrambe le opzioni funzionalmente equivalenti.)
Ovviamente, essendo una proposta nuova di zecca in una specifica nuova di zecca, questa probabilmente non vedrà l'implementazione fino a pochi anni dopo. Nel frattempo, dovrai continuare a utilizzare uno script, come sopra.
1 Se si specifica un tipo o un selettore universale, deve essere il primo. Tuttavia, questo non cambia il modo in cui funzionano fondamentalmente i selettori; non è altro che un capriccio sintattico.
2 Questo è stato originariamente proposto in quanto :nth-match()
, tuttavia, poiché conta ancora un elemento relativo solo ai suoi fratelli, e non a ogni altro elemento che corrisponde al selettore dato, dal 2014 è stato invece riproposto come un'estensione dell'esistente :nth-child()
.