css Advanced 4 min

Selettori CSS avanzati: nth-child, nth-of-type e :has()

:has() come selettore padre, :nth-child con selettore, :not() complesso, casi d'uso pratici

· 726 parole

Nella pillola sui selettori di base abbiamo visto tipo, classe, id e i combinatori. Qui saliamo di livello: quattro strumenti che permettono di scegliere elementi per posizione, per contenuto e per esclusione: cose impossibili (o scomodissime) con i selettori semplici.

I filtri avanzati li possiamo associare a quando, in un negozio di abbigliamento, chiediamo al comesso: «vorrei provare la terza maglietta da sinistra», «vorrei vedere le t-shirt in offerta», «voglio provare tutti i pantaloni con taglia 48».

1. :nth-child(): scegliere per posizione

:nth-child() seleziona un elemento in base alla sua posizione tra tutti i fratelli, a prescindere dal tipo di tag. Accetta parole chiave (odd, even) o la formula An+B, dove A è il passo e B lo scarto.

tr:nth-child(odd) { 
     background: #f4f2f8; 
} /* righe dispari, effetto zebra */ 

li:nth-child(3n) { 
     color: purple; 
} /* ogni terzo elemento: 3, 6, 9... */ 

li:nth-child(3n+1) { 
     font-weight: bold; 
} /* inizio di ogni gruppo: 1, 4, 7... */

Attenzione: conta tutti i fratelli, non solo quelli dello stesso tag. p:nth-child(2) seleziona un <p> solo se è proprio lui il secondo figlio: se il secondo figlio è un <h2>, non scatta nulla.

Fonte: MDN Web Docs: «:nth-child()»: conta gli indici tra tutti i figli del genitore.

2. :nth-of-type(): scegliere per posizione E tipo

:nth-of-type() funziona come :nth-child(), ma conta solo tra i fratelli dello stesso tag. È la scelta giusta quando ti interessa «il secondo paragrafo», non «il secondo figlio, qualunque cosa sia».

<style>
p:nth-child(2) { }  /* NON scatta: il 2 figlio e' il primo <p>, non il secondo */ 
p:nth-of-type(2) { } /* scatta: e' il 2 <p> tra i <p> */
</style>
<h2>Titolo</h2> 
<p>Primo paragrafo</p> 
<p>Secondo paragrafo</p> 

nth-child è come chiamare «il terzo in fila», chiunque sia. nth-of-type è chiamare «il terzo dei camerieri in fila», ignorando chi non è cameriere. Stesso posto, criterio diverso.

Fonte: MDN Web Docs: «:nth-child()» / «:nth-of-type()»: la differenza è cosa viene contato.

3. :nth-child() con selettore: il meglio dei due mondi

Dal 2023 (CSS Selectors Level 4), :nth-child() accetta anche un secondo argomento con la sintassi of <selettore>: prima filtra gli elementi che corrispondono al selettore, poi applica la posizione.

/* i primi 3 elementi della lista che hanno anche classe .important */ 
li:nth-child(-n + 3 of .important) { 
   border: 2px solid orange; 
} 

/* righe pari, ma solo tra quelle NON nascoste */ 
tr:nth-child(even of :not([hidden])) { 
   background: lightyellow; 
}

Utilissimo con righe di tabella nascoste dinamicamente (filtri, ricerche): senza of, :nth-child(even) continuerebbe a contare anche le righe con hidden, sfalsando lo zebra striping visivo.

4. :has(): il selettore «padre» che mancava

Per vent'anni CSS non ha mai potuto selezionare un elemento in base a cosa contiene: solo il contrario (figlio in base al genitore). :has() chiude quel buco: rappresenta un elemento se al suo interno (o accanto) trova una corrispondenza.

/* la card SOLO se contiene un'immagine */ 
article:has(img) { 
   border: 1px solid #ccc; 
} 

/* l'h1 SOLO se e' subito seguito da un h2 (selettore fratello precedente) */ 
h1:has(+ h2) { 
   margin-bottom: 0; 
} 

/* il form-group SOLO se l'input al suo interno e' invalido */ 
.form-group:has(input:invalid) { 
   outline: 2px solid crimson; 
}

:has() è più di un «selettore padre»: MDN lo definisce relazionale: con il combinatore + diventa perfino un selettore per il fratello precedente, altra cosa impossibile prima. Nota: prende la specificità del suo argomento più specifico, e non si può annidare dentro un altro :has().

Fonte: MDN Web Docs: «:has()»: pseudo-classe relazionale per selezionare un genitore o un fratello precedente.

5. :not() complesso: escludere con più criteri

:not() storicamente accettava un solo selettore semplice. Oggi, con Selectors Level 4, accetta una lista di selettori, anche complessi, separati da virgola.

/* esclude sia .draft sia .archived in un colpo solo */ 
article:not(.draft, .archived) { 
   display: block; 
} 

/* combinato con :has(): card senza badge e senza immagine */ 
.card:not(:has(.badge)):not(:has(img)) { 
   opacity: 0.6; 
}

Fonte: MDN Web Docs: «:not()»: accetta una lista di selettori complessi (complex-selector-list).

In sintesi

Selettore Cosa fa Esempio
:nth-child() Posizione tra tutti i fratelli li:nth-child(3n)
:nth-of-type() Posizione tra fratelli dello stesso tag p:nth-of-type(2)
:nth-child(of S) Posizione dopo aver filtrato per selettore li:nth-child(-n+3 of .important)
:has() Elemento che contiene (o precede) un match article:has(img)
:not() con lista Esclude più selettori insieme article:not(.draft, .archived)

Questi selettori spostano in CSS logica che prima richiedeva JavaScript: filtrare per posizione, reagire al contenuto, escludere più casi insieme.

selettore
Accedi o registrati per votare, salvare o commentare la pillola

Commenti (0)

Registrati per commentare, fare domande e proporre l'argomento della prossima pillola (oppure accedi se hai già un account).

Nessun commento. Sii il primo a scrivere qualcosa.

Pillole correlate