web-dev-qa-db-fra.com

Sélecteur CSS pour premier élément avec classe

J'ai un tas d'éléments avec un nom de classe red, mais je n'arrive pas à sélectionner le premier élément avec le class="red" à l'aide de la règle CSS suivante:

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

Quel est le problème dans ce sélecteur et comment puis-je le corriger?

Grâce aux commentaires, j'ai compris que l'élément devait être le premier enfant de son parent à être sélectionné, ce qui n'est pas le cas que j'ai. J'ai la structure suivante et cette règle échoue comme mentionné dans les commentaires:

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

Comment puis-je cibler le premier enfant avec la classe red?

773
Rajat

C’est l’un des exemples les plus connus d’auteurs qui ont mal compris comment fonctionne :first-child. Introduit dans CSS2 , la pseudo-classe :first-child représente le tout premier enfant de son parent . C'est tout. Il existe une idée fausse très répandue selon laquelle il sélectionne l'élément enfant qui est le premier à correspondre aux conditions spécifiées par le reste du sélecteur de composé. En raison de la manière dont les sélecteurs fonctionnent (voir ici pour une explication), ce n'est tout simplement pas vrai.

Le sélecteur de niveau 3 introduit une pseudo-classe :first-of-type_ , qui représente le premier élément parmi les frères et soeurs de son type d'élément. Cette réponse explique, avec des illustrations, la différence entre :first-child et :first-of-type. Cependant, comme avec :first-child, il n’examine aucune autre condition ni aucun autre attribut. En HTML, le type d'élément est représenté par le nom de la balise. Dans la question, ce type est p.

Malheureusement, il n’existe pas de pseudo-classe :first-of-class similaire pour faire correspondre le premier élément enfant d’une classe donnée. Une solution de contournement qui Lea Vero et que j'ai proposée pour cela (bien que de manière totalement indépendante) consiste à appliquer d'abord les styles souhaités à all vos éléments avec cette classe:

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

... puis "annule" les styles pour les éléments de la classe qui vient après le premier, en utilisant le combinateur de même parent ~ dans une règle primordiale:

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

Maintenant, seul le premier élément avec class="red" aura une bordure.

Voici une illustration de l'application des règles:

<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. Aucune règle n'est appliquée; aucune bordure n'est rendue.
    Cet élément n'a pas la classe red, il est donc ignoré.

  2. Seule la première règle est appliquée; une bordure rouge est rendue.
    Cet élément a la classe red, mais il n'est précédé d'aucun élément ayant la classe red dans son parent. Ainsi, la deuxième règle n'est pas appliquée, seule la première et l'élément conserve sa frontière.

  3. Les deux règles sont appliquées; aucune bordure n'est rendue.
    Cet élément a la classe red. Il est également précédé par au moins un autre élément de classe red. Ainsi, les deux règles sont appliquées et la seconde déclaration border prime sur la première, la "défaisant" pour ainsi dire.

En prime, bien qu’il ait été introduit dans Selectors 3, le combinateur de frères et soeurs général est en fait assez bien supporté par IE7 et les versions plus récentes, à la différence de :first-of-type et de :nth-of-type() qui ne sont supportés que par IE9. Si vous avez besoin d'un bon support du navigateur, vous avez de la chance.

En fait, le fait que le combinateur de fratrie soit le seul composant important de cette technique, et ​​il possède un support de navigateur aussi incroyable, rend cette technique très polyvalente - vous pouvez l'adapter pour filtrer des éléments par d'autres choses, en plus des sélecteurs de classe:

  • Vous pouvez utiliser ceci pour contourner :first-of-type dans IE7 et IE8, en fournissant simplement un sélecteur de type au lieu d'un sélecteur de classe (à nouveau, pour en savoir plus sur son utilisation incorrecte ici, dans une section ultérieure):

    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 */
    }
    
  • Vous pouvez filtrer par sélecteurs d'attributs ou par tout autre sélecteur simple à la place des classes.

  • Vous pouvez également combiner cette technique prioritaire avec pseudo-éléments même si, techniquement, les pseudo-éléments ne sont pas de simples sélecteurs.

Notez que pour que cela fonctionne, vous devez savoir à l'avance quels styles seront par défaut pour les autres éléments frères afin que vous puissiez remplacer la première règle. De plus, étant donné que cela implique le contournement des règles en CSS, vous ne pouvez pas obtenir la même chose avec un sélecteur unique à utiliser avec les localisateurs CSS de API de sélecteurs , ou de Selenium .

Il est à noter que Selectors 4 introduit ne extension de la notation :nth-child() (à l'origine une pseudo-classe entièrement nouvelle appelée :nth-match()), qui vous permettra d'utiliser quelque chose comme :nth-child(1 of .red) au lieu d'un hypothétique .red:first-of-class. Étant une proposition relativement récente, il n’ya pas encore suffisamment d’implémentations interopérables pour pouvoir être utilisée dans les sites de production. Espérons que cela va bientôt changer. En attendant, la solution de rechange que j'ai suggérée devrait fonctionner dans la plupart des cas.

Gardez à l'esprit que cette réponse suppose que la question recherche chaque premier élément enfant ayant une classe donnée. Il n’existe pas de pseudo-classe ni même de solution CSS générique pour la nième correspondance d’un sélecteur complexe sur tout le document ​​- l’existence d’une solution dépend fortement de la structure du document. jQuery fournit :eq(), :first, :last et plus à cette fin, mais notez à nouveau que ils fonctionnent très différemment de :nth-child() et al . À l'aide de l'API Selectors, vous pouvez utiliser document.querySelector() pour obtenir la toute première correspondance:

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

Ou utilisez document.querySelectorAll() avec un indexeur pour choisir une correspondance spécifique:

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

Bien que la solution .red:nth-of-type(1) dans la réponse acceptée initiale par Philip Daubmeier fonctionne (qui a été écrite à l'origine par Martyn mais supprimée depuis), elle ne se comporte pas comme prévu. à.

Par exemple, si vous ne vouliez sélectionner que la variable p dans votre balisage d'origine:

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

... alors vous ne pouvez pas utiliser .red:first-of-type (équivalent à .red:nth-of-type(1)), car chaque élément est le premier (et le seul) de son type (p et div respectivement), donc les deux seront mis en correspondance par le sélecteur.

Lorsque le premier élément d'une certaine classe est également le premier de son type, la pseudo-classe fonctionnera, mais cela ne se produit que par coïncidence . Ce comportement est démontré dans la réponse de Philip. Au moment où vous vous en tenez à un élément du même type avant cet élément, le sélecteur échouera. Prendre le balisage mis à jour:

<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'application d'une règle avec .red:first-of-type fonctionnera, mais une fois que vous aurez ajouté une autre p sans 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>

... le sélecteur échouera immédiatement, car le premier élément .red est maintenant l'élément secondp.

1317
BoltClock

Le sélecteur :first-child a pour but, comme son nom l'indique, de sélectionner le premier enfant d'une balise parent. Les enfants doivent être incorporés dans la même balise parent. Votre exemple exact fonctionnera (je l’ai juste essayé ici ):

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

Peut-être avez-vous imbriqué vos balises dans différentes balises parent? Vos tags de classe red sont-ils vraiment les premiers tags sous le parent?

Notez également que cela ne s'applique pas uniquement à la première balise de ce type dans l'ensemble du document, mais chaque fois qu'un nouveau parent est enroulé autour de celle-ci, comme:

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

first et third seront alors rouges.

Mettre à jour:

Je ne sais pas pourquoi Martyn a supprimé sa réponse, mais il avait la solution, le sélecteur :nth-of-type:

<html>
<head>
<style type="text/css">
.red:nth-of-type(1)
{
    border:5px solid red;
} 
</style>
</head>

<body>
    <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>
</body>
</html>

Crédits à Martyn . Plus d'infos par exemple ici . Sachez qu’il s’agit d’un sélecteur CSS 3; par conséquent, tous les navigateurs ne le reconnaîtront pas (par exemple, IE8 ou une version antérieure).

309
Philip Daubmeier

La bonne réponse est:

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

Partie I: Si l’élément est le premier de son parent et a la classe "rouge", il aura une bordure.
Partie II: Si l’élément ".red" n’est pas le premier, mais suit immédiatement un élément sans classe ".red", il mérite également l’honneur de cette bordure.

Fiddle ou ce n'est pas arrivé.

La réponse de Philip Daubmeier, bien qu'acceptée, n'est pas correcte - voir le violon ci-joint.
La réponse de BoltClock fonctionnerait, mais définirait et écraserait inutilement les styles
(particulièrement un problème qui hériterait d’une bordure différente - vous ne voulez pas déclarer d’autres frontières à la frontière: aucune)

EDIT: Dans le cas où vous avez "rouge" suivi plusieurs fois sans rouge, chaque "premier" rouge aura la bordure. Pour éviter cela, il faudrait utiliser la réponse de BoltClock. Voir violon

64
SamGoody

vous pouvez utiliser first-of-type ou nth-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>

14
Moes

Pour correspondre à votre sélecteur, l'élément doit avoir un nom de classe de red et doit être le premier enfant de son parent.

<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>
9
Chetan Sastry

Etant donné que les autres réponses couvrent ce qui {mal} _, je vais essayer l'autre moitié, comment y remédier. Malheureusement, je ne sais pas que vous avez un CSS uniquement solution ici, au moins pas à quoi je puisse penser. Il y a quelques autres options cependant ....

  1. Attribuez une classe first à l'élément lorsque vous le générez, comme suit:

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

    CSS:

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

    Ce CSS ne fait correspondre que les éléments avec les classes deux first et red

  2. Vous pouvez également faire la même chose en JavaScript. Par exemple, voici ce que jQuery vous utiliseriez pour cela, en utilisant le même CSS que ci-dessus:

    $(".red:first").addClass("first");
    
8
Nick Craver

Selon votre problème mis à jour

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

que diriez-vous 

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

Ceci sélectionnera class home, puis l'élément span et enfin tous les éléments .red placés immédiatement après les éléments span. 

Référence: http://www.w3schools.com/cssref/css_selectors.asp

5
StinkyCat

Les réponses ci-dessus sont trop complexes. 

.class:first-of-type { }

Cela sélectionnera le premier type de classe. Source MDN

4
Gabriel Fair

J'utilise ci-dessous CSS pour avoir une image de fond pour la liste 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>

3
li bing zhao

Je l'ai eu dans mon projet.

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>

3
Yener Örer

Vous pouvez utiliser nth-of-type (1) mais assurez-vous que le site n'a pas besoin de supporter IE7, etc., si c'est le cas, utilisez jQuery pour ajouter une classe de corps, puis rechercher un élément via la classe de corps IE7, puis le nom de l'élément, puis ajouter dans le style nth-child à elle.

3
Jamie Paterson

Vous pouvez changer votre code pour quelque chose comme ça pour que ça marche

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

Cela fait le travail pour vous

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

Voici une référence CSS de SnoopCode about that.

3
Prabhakar

Essaye ça :

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

Essayez ceci simple et efficace

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

Pour une raison quelconque, aucune des réponses ci-dessus ne semblait traiter le cas de le vrai premier et seul premier enfant du parent.

#element_id > .class_name:first-child

Toutes les réponses ci-dessus échoueront si vous souhaitez appliquer le style uniquement au premier enfant de classe de ce code.

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

Essayez cette solution:

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

Lien CodePen

0
Santosh Khalse

Nécessaire seulement en premier et un seul paragraphe en rouge. Comment?

<!DOCTYPE html><html><head><style>

article p:nth-child(1){background: red}
article p:first-child{background: red}

</style></head><body>

<p style="color:blue">Needed only first and only one paragraph had red. How?</p>

<article>
<p>The first paragraph.</p>
<div><p>The second paragraph.</p></div>
<p>The third paragraph.</p>
<div><p>The fourth paragraph.</p></div>
</article>

</body></html>

0