Posso combinare: nth-child () o: nth-of-type () con un selettore arbitrario?


117

C'è un modo per selezionare ogni ennesimo figlio che corrisponde (o non corrisponde) a un selettore arbitrario ? Ad esempio, voglio selezionare ogni riga dispari della tabella, ma all'interno di un sottoinsieme di righe:

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>

Ma :nth-child()sembra proprio per contare tutti gli trelementi, indipendentemente dal fatto o meno che siano della classe "riga", così finisco con quello anche elemento di "riga" invece dei due che sto cercando. La stessa cosa accade con :nth-of-type().

Qualcuno può spiegare perché?

Risposte:


144

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+bdove a != 1e 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 trelementi o un elemento di lista i cui unici figli sono lielementi, 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 trelemento che soddisfi tutte le seguenti condizioni indipendenti:

  • è un figlio dispari del suo genitore;
  • ha la classe "riga"; e
  • è un discendente di un tableelemento 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 trelementi 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 tre :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 trelementi 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().


3
"(noterai il mio uso di un elenco non ordinato qui, solo per portare a casa il punto)" Vorrei che più persone fossero così consapevoli del loro uso di proiettili ordinati e non ordinati. La ringrazio per la risposta.
The Red Pea

1
@ The Red Pea: Uno dei miei più grandi problemi di HTML: "In ordine dal più alto / più basso al più basso / più alto:" seguito da un elenco non ordinato. Voglio dire, dai, sul serio?
BoltClock

6

Non proprio..

citazione dai documenti

La :nth-childpseudo-classe corrisponde a un elemento che ha un fratello + b-1 prima di esso nell'albero del documento , per un dato valore positivo o zero per n, e ha un elemento genitore.

È un selettore a sé stante e non si combina con le classi. Nella tua regola deve solo soddisfare entrambi i selettori allo stesso tempo, quindi mostrerà le :nth-child(even)righe della tabella se anche loro hanno la .rowclasse.


0

nth-of-typefunziona in base all'indice dello stesso tipo di elemento ma nth-childfunziona solo in base all'indice indipendentemente dal tipo di elementi fratelli.

Per esempio

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

Supponiamo di voler nascondere nell'html sopra tutti gli elementi con classe rest.

In questo caso nth-childe nth-of-typefunzionerà esattamente come tutti gli elementi sono dello stesso tipo che <div>dovrebbe essere 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;
}

Ora ti starai chiedendo qual è la differenza tra nth-childe nth-of-typequindi questa è la differenza

Supponiamo che l'html sia

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

Nell'html sopra il tipo di .restelementoèdifferente dagli altri .restsono i paragrafi e gli altri sono div quindi in questo caso se lo usi nth-childdevi scrivere così

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

ma se usi l'ennesimo tipo di CSS può essere questo

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

Come il tipo di .restelemento è <p>così qui nth-of-typesta rilevando il tipo di .reste poi ha applicato CSS sul 1 °, 2 °, 3 °, 4 °, 5 ° elemento di <p>.


Quanto è utile per i <tr>tag?
Alexis Wilke

0

Potresti essere in grado di farlo con xpath. qualcosa di simile //tr[contains(@class, 'row') and position() mod 2 = 0]potrebbe funzionare. Ci sono altre domande SO che espandono i dettagli su come abbinare le classi in modo più preciso.


0

Ecco la tua risposta

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

0

Tutte le domande sull'uso di nth-child e sul saltare i tag nascosti sembrano reindirizzare come duplicati di questo, quindi lo lascerò qui. Mi sono imbattuto in questo blog https://blog.blackbam.at/2015/04/09/css-nth-child-selector-ignore-hidden-element/ che utilizza un approccio css intelligente per far sì che l'ennesimo bambino ignori gli elementi nascosti, come segue:

Il seguente CSS aggiunge un margine diritto a ogni secondo elemento visibile, indipendentemente da quale elemento abbia la classe 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;
}

Spero che questo aiuti qualcuno che sta seguendo la scia dell'inganno per ignorare le domande sugli elementi nascosti!


1
Mi piacerebbe esprimere un voto positivo, ma ha bisogno di una demo funzionante.
Moob

Il mio ricordo è che in realtà non era così solido come sembrava inizialmente - ora andrei con il commento più votato, questo non è possibile.
IrishDubGuy

0

SE hai la stessa classe genitore per tutti i selettori, allora usi quella classe document.querySelector("main .box-value:nth-child(3) select.priorityOption"); perché in quel caso document.querySelector("main .box-value select.priorityOption:nth-child(3)");non funziona. Grazie

<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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.