Selettore CSS per il primo elemento con classe


947

Ho un sacco di elementi con un nome di classe red, ma non riesco a selezionare il primo elemento class="red"usando la seguente regola CSS:

.red:first-child {
    border: 5px solid red;
}
<p class="red"></p>
<div class="red"></div>

Cosa c'è di sbagliato in questo selettore e come posso correggerlo?

Grazie ai commenti, ho capito che l'elemento deve essere il primo figlio del suo genitore a essere selezionato, il che non è il mio caso. Ho la seguente struttura e questa regola fallisce come menzionato nei commenti:

.home .red:first-child {
    border: 1px solid red;
}
<div class="home">
    <span>blah</span>
    <p class="red">first</p>
    <p class="red">second</p>
    <p class="red">third</p>
    <p class="red">fourth</p>
</div>

Come posso scegliere come target il primo bambino con classe red?


per quelli che si stanno confondendo a causa di diversi tipi di elementi nel mio esempio (p, div), anche farli uguali non funziona e il problema persiste.
Rajat,

4
Penso che sia così che il selettore del primo figlio avrebbe dovuto funzionare ...
Felix Eve,

28
: il primo figlio non sarebbe un ottimo nome allora. Se avessi un figlio e poi una figlia, non chiameresti tua figlia il tuo primogenito. Allo stesso modo, il primo .home> .red non è il primo figlio di .home, quindi sarebbe inappropriato chiamarlo come tale.
BoltClock

No, è come: il primo di tipo avrebbe dovuto funzionare
Evan Thompson il

@EvanThompson Ecco come :first-of-type fa il lavoro.
TylerH,

Risposte:


1427

Questo è uno degli esempi più noti di autori che fraintendono il modo in cui :first-childfunziona. Introdotta in CSS2 , la :first-childpseudo-classe rappresenta il primogenito del suo genitore . Questo è tutto. C'è un malinteso molto comune sul fatto che raccoglie qualunque elemento figlio sia il primo a soddisfare le condizioni specificate dal resto del selettore composto. A causa del modo in cui funzionano i selettori (vedere qui per una spiegazione), semplicemente non è vero.

Il livello 3 dei selettori introduce una :first-of-typepseudo-classe , che rappresenta il primo elemento tra i fratelli del suo tipo di elemento. Questa risposta spiega, con illustrazioni, la differenza tra :first-childe :first-of-type. Tuttavia, come nel caso :first-child, non considera altre condizioni o attributi. In HTML, il tipo di elemento è rappresentato dal nome del tag. Nella domanda, quel tipo è p.

Sfortunatamente, non esiste una :first-of-classpseudo-classe simile per abbinare il primo elemento figlio di una data classe. Una soluzione alternativa che Lea Verou ed io abbiamo escogitato per questo (anche se in modo totalmente indipendente) è applicare prima gli stili desiderati a tutti i tuoi elementi con quella classe:

/* 
 * Select all .red children of .home, including the first one,
 * and give them a border.
 */
.home > .red {
    border: 1px solid red;
}

... quindi "annulla" gli stili per gli elementi con la classe che segue la prima , usando il combinatore di fratelli generali~ in una regola prioritaria:

/* 
 * Select all but the first .red child of .home,
 * and remove the border from the previous rule.
 */
.home > .red ~ .red {
    border: none;
}

Ora solo il primo elemento con class="red"avrà un bordo.

Ecco un'illustrazione di come vengono applicate le regole:

<div class="home">
  <span>blah</span>         <!-- [1] -->
  <p class="red">first</p>  <!-- [2] -->
  <p class="red">second</p> <!-- [3] -->
  <p class="red">third</p>  <!-- [3] -->
  <p class="red">fourth</p> <!-- [3] -->
</div>
  1. Non vengono applicate regole; nessun bordo viene reso.
    Questo elemento non ha la classe red, quindi viene saltato.

  2. Viene applicata solo la prima regola; viene visualizzato un bordo rosso.
    Questo elemento ha la classe red, ma non è preceduto da alcun elemento con la classe rednel suo genitore. Pertanto la seconda regola non viene applicata, solo la prima e l'elemento mantiene il suo bordo.

  3. Vengono applicate entrambe le regole; nessun bordo viene reso.
    Questo elemento ha la classe red. È inoltre preceduto da almeno un altro elemento con la classe red. In tal modo vengono applicate entrambe le regole e la seconda borderdichiarazione sovrascrive la prima, quindi "annullandola", per così dire.

Come bonus, sebbene sia stato introdotto in Selettori 3, il combinatore di fratelli generali è in realtà abbastanza ben supportato da IE7 e più recenti, a differenza :first-of-typee :nth-of-type()che sono supportati solo da IE9 in poi. Se hai bisogno di un buon supporto per il browser, sei fortunato.

In effetti, il fatto che il combinatore di pari livello sia l'unico componente importante di questa tecnica e abbia un supporto del browser così straordinario, rende questa tecnica molto versatile: puoi adattarla per filtrare gli elementi con altre cose, oltre ai selettori di classe:

  • Puoi usarlo per aggirare :first-of-typeIE7 e IE8, semplicemente fornendo un selettore di tipo anziché un selettore di classe (di nuovo, più sul suo uso errato qui in una sezione successiva):

    article > p {
        /* Apply styles to article > p:first-of-type, which may or may not be :first-child */
    }
    
    article > p ~ p {
        /* Undo the above styles for every subsequent article > p */
    }
  • È possibile filtrare per selettori di attributo o qualsiasi altro selettore semplice anziché per classe.

  • Puoi anche combinare questa tecnica prioritaria con pseudo-elementi anche se tecnicamente gli pseudo-elementi non sono semplici selettori.

Nota che per far funzionare tutto ciò, dovrai sapere in anticipo quali saranno gli stili predefiniti per gli altri tuoi fratelli e sorelle in modo da poter sovrascrivere la prima regola. Inoltre, poiché ciò implica l'override delle regole nei CSS, non è possibile ottenere la stessa cosa con un singolo selettore da utilizzare con l' API Selector o Selenium i localizzatori CSS di .

Vale la pena ricordare che Selectors 4 introduce un'estensione alla :nth-child()notazione (originariamente una pseudo-classe completamente nuova chiamata :nth-match()), che ti permetterà di usare qualcosa di simile :nth-child(1 of .red)al posto di un ipotetico .red:first-of-class. Essendo una proposta relativamente recente, non ci sono abbastanza implementazioni interoperabili per essere utilizzabili nei siti di produzione. Spero che questo cambierà presto. Nel frattempo, la soluzione che ho suggerito dovrebbe funzionare nella maggior parte dei casi.

Tieni presente che questa risposta presuppone che la domanda cerchi ogni primo elemento figlio che ha una determinata classe. Non esiste una pseudo-classe né una soluzione CSS generica per l'ennesima corrispondenza di un selettore complesso in tutto il documento - se esiste una soluzione dipende fortemente dalla struttura del documento. jQuery fornisce :eq(), :first, :laste più per questo scopo, ma nota ancora che essi funzionano in modo molto diverso da :nth-child()et al . Utilizzando l'API Selettori, è possibile utilizzare document.querySelector()per ottenere la prima corrispondenza:

var first = document.querySelector('.home > .red');

Oppure usa document.querySelectorAll()con un indicizzatore per scegliere una corrispondenza specifica:

var redElements = document.querySelectorAll('.home > .red');
var first = redElements[0];
var second = redElements[1];
// etc

Sebbene la .red:nth-of-type(1)soluzione nella risposta originale accettata da Philip Daubmeier funzioni (che è stata originariamente scritta da Martyn ma cancellata da allora), non si comporta come ti aspetteresti.

Ad esempio, se si desidera selezionare solo il pmarkup originale:

<p class="red"></p>
<div class="red"></div>

... quindi non puoi usare .red:first-of-type(equivalente a .red:nth-of-type(1)), perché ogni elemento è il primo (e unico) uno del suo tipo ( pe divrispettivamente), quindi entrambi saranno abbinati dal selettore.

Quando il primo elemento di una determinata classe è anche il primo del suo tipo , la pseudo-classe funzionerà, ma ciò accade solo per coincidenza . Questo comportamento è dimostrato nella risposta di Filippo. Nel momento in cui ti attacchi a un elemento dello stesso tipo prima di questo elemento, il selettore fallirà. Prendendo il markup aggiornato:

<div class="home">
  <span>blah</span>
  <p class="red">first</p>
  <p class="red">second</p>
  <p class="red">third</p>
  <p class="red">fourth</p>
</div>

L'applicazione di una regola con .red:first-of-typefunzionerà, ma una volta aggiunta un'altra psenza la classe:

<div class="home">
  <span>blah</span>
  <p>dummy</p>
  <p class="red">first</p>
  <p class="red">second</p>
  <p class="red">third</p>
  <p class="red">fourth</p>
</div>

... il selettore fallirà immediatamente, perché il primo .redelemento è ora il secondo p elemento.


15
Quindi, c'è un modo per emulare :last-of-class? Seleziona l'ultimo elemento di una classe.
Rocket Hazmat,

1
@Rocket: Non che io possa vedere :(
BoltClock

4
Bella tecnica con il fratello. Vale la pena notare che funziona anche con più combinatori di pari livello, ad esempio p ~ p ~ p selezionerà il terzo elemento e oltre: jsfiddle.net/zpnnvedm/1
Legolas

2
@BoltClock Sì, scusa, sono venuto qui per una soluzione e non mi importava molto del caso specifico dell'OP. In realtà non riesco a capire perché funzioni general sibling selector ~come :not(:first-of-*)per un tipo specifico, presumo che dovrebbe applicare la regola a ciascun elemento corrispondente, ma viene applicato solo per la prima corrispondenza anche quando ci sono 3 o più corrispondenze possibili.
Gerard Reches,

2
Secondo caniuse l' :nth-child(1 of .foo)estensione è già stata implementata su Safari 9.1+. (Non ho controllato però)
Danield

330

Il :first-childselettore intende, come dice il nome, selezionare il primo figlio di un tag principale. I bambini devono essere incorporati nello stesso tag principale. Il tuo esempio esatto funzionerà (appena provato qui ):

<body>
    <p class="red">first</p>
    <div class="red">second</div>
</body>

Forse hai nidificato i tuoi tag in diversi tag principali? I tuoi tag di classe sono reddavvero i primi tag sotto il genitore?

Si noti inoltre che ciò non si applica solo al primo tag di questo tipo nell'intero documento, ma ogni volta che un nuovo genitore viene avvolto attorno ad esso, come:

<div>
    <p class="red">first</p>
    <div class="red">second</div>
</div>
<div>
    <p class="red">third</p>
    <div class="red">fourth</div>
</div>

firste thirdsarà rosso allora.

Aggiornare:

Non so perché Martyn abbia cancellato la sua risposta, ma aveva la soluzione, il :nth-of-typeselettore:

.red:nth-of-type(1)
{
    border:5px solid red;
} 
<div class="home">
    <span>blah</span>
    <p class="red">first</p>
    <p class="red">second</p>
    <p class="red">third</p>
    <p class="red">fourth</p>
</div>

Crediti a Martyn . Altre informazioni per esempio qui . Tieni presente che si tratta di un selettore CSS 3, pertanto non tutti i browser lo riconosceranno (ad es. IE8 o precedente).


Potrebbe essere stata colpa mia - come avevo fatto notare a Martyn che un selettore CSS3 come lui :nth-of-typesoffre del leggero problema di non funzionare affatto in nessuna versione attuale di IE.
Már Örlygsson,

25
Mi sono un po 'confuso leggendo questo. .red:nth-of-type(1)Selezionerà rigorosamente qualsiasi elemento che (a) è il primo figlio del suo tipo di elemento e (b) ha la classe "rosso". Quindi, se, nell'esempio, il primo <p> non avesse la classe "rosso", non verrebbe selezionato. In alternativa, se <span> e il primo <p> avessero entrambi la classe "rosso", sarebbero stati entrambi selezionati. jsfiddle.net/fvAxn
David,

7
@Dan Mundy: :first-of-typeè equivalente a :nth-of-type(1), quindi ovviamente funziona anche. Può anche fallire allo stesso modo per lo stesso motivo indicato nella mia risposta.
BoltClock

4
@David Sono sicuro che :nth-of-typesignifica "elemento / tag" quando dice "tipo". Quindi considera solo l'elemento, non cose come le classi.
gcampbell,

2
@gcampbell: Sì, è esattamente quello che significa, ed è per questo che questa risposta è imperfetta. Il motivo per cui è stata scelta la parola "tipo" è di non accoppiare i selettori con HTML / XML, poiché non tutte le lingue hanno un concetto di "tag" che definiscono gli elementi.
BoltClock

74

La risposta corretta è:

.red:first-child, :not(.red) + .red { border:5px solid red }

Parte I: Se l'elemento è il primo a essere il suo genitore e ha una classe "rossa", otterrà il bordo.
Parte II: Se l'elemento ".red" non è il primo a essere il suo genitore, ma segue immediatamente un elemento senza classe ".red", deve anche meritare l'onore di detto bordo.

Fiddle o non è successo.

La risposta di Philip Daubmeier, sebbene accettata, non è corretta - vedi il violino in allegato.
La risposta di BoltClock funzionerebbe, ma definisce e sovrascrive inutilmente gli stili
(in particolare un problema in cui altrimenti erediterebbe un bordo diverso - non si vuole dichiarare altro al bordo: nessuno)

MODIFICA: Nel caso in cui il "rosso" segua diverse volte il rosso, ogni "primo" rosso otterrà il bordo. Per evitarlo, si dovrebbe usare la risposta di BoltClock. Vedi violino


2
Questa risposta non è sbagliata, il selettore è corretto per il markup dato, ma devo ribadire che la situazione menzionata nella modifica è il motivo per cui dichiaro che è necessario un override almeno quando non è possibile garantire la struttura del markup - solo perché un .redsegue a :not(.red)non sempre lo rende il primo .redtra i suoi fratelli. E se il confine deve essere ereditato, si tratta semplicemente di dichiarare border: inheritanziché border: nonenella regola di sostituzione.
BoltClock

3
Questa soluzione è la migliore IMO perché puoi facilmente fare lo stesso per l'ultimo figlio.
A1rPun

@ A1rPun Come si cambia questo per l'ultimo figlio?
Willem,

@Willem Basta passare first-childa last-child, ma dopo il test vedo che questo non fa sempre il trucco.
A1rPun

3
Mi dispiace, ma non corrisponde al "primo elemento figlio con classe .red", ma corrisponde al "primo elemento se ha classe .red e primo elemento .red dopo un elemento non .red". Questi due non sono equivalenti. Fiddle: jsfiddle.net/Vq8PB/166
Gunchars

19

potresti usare first-of-typeonth-of-type(1)

.red {
  color: green;  
}

/* .red:nth-of-type(1) */
.red:first-of-type {
  color: red;  
}
<div class="home">
  <span>blah</span>
  <p class="red">first</p>
  <p class="red">second</p>
  <p class="red">third</p>
  <p class="red">fourth</p>
</div>


6
Non funzionerà se hai <p></p>tra il spane il tuo primo pelemento con la redclasse. Guarda questo JSFiddle .
Francisco Romero,

1
Ho visto ora che riproduce nell'ultimo esempio della sua risposta lo stesso comportamento che ho indicato qui. Quando ho provato il tuo esempio e "giocato" un po ', noto quel comportamento e volevo sottolineare in modo che i futuri lettori ne fossero a conoscenza.
Francisco Romero,

13

Le risposte sopra sono troppo complesse.

.class:first-of-type { }

Questo selezionerà il primo tipo di classe. Fonte MDN


4
Non riesco a trovare alcun riferimento al primo tipo e il primo tipo si applica solo al nome del tag; sei sicuro che questa risposta sia corretta?
Matt Broatch,

1
first-type è stato rinominato in first-of-type
Gabriel Fair il

7
Non funziona con le classi. Ecco come dovrebbe funzionare, perché selezionare l'ennesimo di una classe sarebbe più utile che selezionare l'ennesimo di un tag. Ma ': first-of-type' ha funzionato solo con tagName. Se succede così che "first-of-class" e "first-of-tag" si riferiscono allo stesso elemento, cosa che fanno spesso, è facile confondersi nel pensare che funzioni in quel modo; e poi chiedersi cosa non funziona quando si arriva a un caso in cui non lo fanno.
Evan Thompson

2
Non sono sicuro del perché questa non sia la risposta selezionata. Questo fa esattamente ciò che l'OP stava chiedendo e funziona perfettamente. SMH.
Bernesto,

1
@Bernesto, quando hai un caso in cui hai più elementi dello stesso "tipo", diciamo <span>, e alcuni hanno la classe highlight. Il .highlight:first-of-typeselettore selezionerà la prima istanza del "tipo" con la classe selezionata, in questo esempio la prima <span>e non la prima istanza della classe highlight. Solo se anche la prima istanza di span ha il clou della classe, lo stile verrà implementato. ( codepen.io/andrewRmillar/pen/poJKJdJ )
Sl4rtib4rtf4st

9

Per abbinare il tuo selettore, l'elemento deve avere un nome di classe rede deve essere il primo figlio del suo genitore.

<div>
    <span class="red"> <!-- MATCH -->
</div>

<div>
    <span>Blah</span>
    <p class="red"> <!-- NO MATCH -->
</div>

<div>
    <span>Blah</span>
    <div><p class="red"></div> <!-- MATCH -->
</div>

questo è corretto e questo sembra essere il mio problema, ma c'è un modo per selezionare il primo elemento con una classe indipendentemente dal fatto che sia preceduto da altri elementi?
Rajat,

Se avessi guardato la risposta di Martyns non dovevi chiedere questo :)
Philip Daubmeier,

9

Poiché le altre risposte riguardano ciò che non va, proverò l'altra metà, come risolverlo. Sfortunatamente, non so che tu abbia una sola soluzione CSS qui, almeno non che io possa pensare . Ci sono alcune altre opzioni però ....

  1. Assegna una firstclasse all'elemento quando la generi, in questo modo:

    <p class="red first"></p>
    <div class="red"></div>

    CSS:

    .first.red {
      border:5px solid red;
    }

    Questo CSS corrisponde solo agli elementi con entrambe first e le redclassi.

  2. In alternativa, fai lo stesso in JavaScript, ad esempio ecco quale jQuery useresti per farlo, usando lo stesso CSS di cui sopra:

    $(".red:first").addClass("first");

Qualche tempo fa ho trovato una soluzione solo per CSS ; L'ho riprodotto qui come una risposta canonica.
BoltClock

1
Finché non c'è niente di simile :first-of-class, suggerirei anche di aggiungere una classe extra al primo elemento. Sembra la soluzione più semplice per ora.
Kai Noack,

7

L'ho preso nel mio progetto.

div > .b ~ .b:not(:first-child) {
	background: none;
}
div > .b {
    background: red;
}
<div>
      <p class="a">The first paragraph.</p>
      <p class="a">The second paragraph.</p>
      <p class="b">The third paragraph.</p>
      <p class="b">The fourth paragraph.</p>
  </div>


5

Secondo il tuo problema aggiornato

<div class="home">
  <span>blah</span>
  <p class="red">first</p>
  <p class="red">second</p>
  <p class="red">third</p>
  <p class="red">fourth</p>
</div>

che ne dite di

.home span + .red{
      border:1px solid red;
    }

Questo selezionerà la classe home , quindi l' intervallo di elementi e infine tutti gli elementi .red posizionati immediatamente dopo gli elementi di intervallo.

Riferimento: http://www.w3schools.com/cssref/css_selectors.asp


3

È possibile utilizzare nth-of-type (1) ma accertarsi che il sito non debba supportare IE7 ecc. In tal caso, utilizzare jQuery per aggiungere la classe del corpo, quindi trovare l'elemento tramite la classe del corpo IE7, quindi il nome dell'elemento, quindi aggiungere nello stile dell'ennesimo figlio.


3

Puoi cambiare il tuo codice in qualcosa del genere per farlo funzionare

<div class="home">
  <span>blah</span>
  <p class="red">first</p>
  <p class="red">second</p>
  <p class="red">third</p>
  <p class="red">fourth</p>
</div>

Questo fa il lavoro per te

.home span + .red{
      border:3px solid green;
    }

Ecco un riferimento CSS da SnoopCode a riguardo.


3

Sto usando il CSS sotto per avere un'immagine di sfondo per l'elenco ul li

#footer .module:nth-of-type(1)>.menu>li:nth-of-type(1){
  background-position: center;
  background-image: url(http://monagentvoyagessuperprix.j3.voyagesendirect.com/images/stories/images_monagentvoyagessuperprix/layout/icon-home.png);
  background-repeat: no-repeat;
}
<footer id="footer">
  <div class="module">
    <ul class="menu ">
      <li class="level1 item308 active current"></li>
      <li> </li>
    </ul> 
  </div>
  <div class="module">
    <ul class="menu "><li></li>
      <li></li> 
    </ul>
  </div>
  <div class="module">
    <ul class="menu ">
      <li></li>
      <li></li>
    </ul>
  </div>
</footer>


2

Prova questo :

    .class_name > *:first-child {
        border: 1px solid red;
    }

2

Per qualche motivo, nessuna delle risposte sopra riportate sembrava affrontare il caso del primo vero e unico primo figlio del genitore.

#element_id > .class_name:first-child

Tutte le risposte di cui sopra falliranno se si desidera applicare lo stile solo al figlio di prima classe all'interno di questo codice.

<aside id="element_id">
  Content
  <div class="class_name">First content that need to be styled</div>
  <div class="class_name">
    Second content that don't need to be styled
    <div>
      <div>
        <div class="class_name">deep content - no style</div>
        <div class="class_name">deep content - no style</div>
        <div>
          <div class="class_name">deep content - no style</div>
        </div>
      </div>
    </div>
  </div>
</aside>

1
La tua risposta è essenzialmente già contenuta nelle prime due risposte più alte a questa domanda e non aggiunge nulla. Inoltre, l'uso della :first-childpseudo-classe è fuorviante poiché si aggiunge .class_nameprima che non cambi il modo in cui funziona e semplicemente lo fa agire come filtro. Se hai un div prima, il <div class="class_name">First content that need to be styled</div>tuo selettore non corrisponderebbe poiché non è il primo figlio reale.
j08691,

Non penso sia così semplice per qualcuno che ha bisogno delle informazioni. E sì, hai ragione sul caso. Questo serve un caso più specifico. Questo è il motivo per cui ho pensato che potesse essere utile.
Yavor Ivanov,

Questo è esattamente ciò di cui avevo bisogno, preciso e conciso. Grazie @YavorIvanov
quantme

1

Prova questo semplice ed efficace

 .home > span + .red{
      border:1px solid red;
    }

-1

Credo che usando il relativo selettore + per la selezione degli elementi posizionati immediatamente dopo, funzioni qui al meglio (come pochi hanno suggerito prima).

È anche possibile per questo caso utilizzare questo selettore

.home p:first-of-type

ma questo è il selettore di elementi non quello di classe uno.

Ecco una bella lista di selettori CSS: https://kolosek.com/css-selectors/


-2

Prova questa soluzione:

 .home p:first-of-type {
  border:5px solid red;
  width:100%;
  display:block;
}
<div class="home">
  <span>blah</span>
  <p class="red">first</p>
  <p class="red">second</p>
  <p class="red">third</p>
  <p class="red">fourth</p>
</div>

Collegamento CodePen


La domanda è " Selettore CSS per il primo elemento con classe ", non " Selettore CSS per il primo elemento con nome tag ".
GeroldBroser ripristina Monica il
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.