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


J'ai un tas d'éléments avec un nom de classe red, mais je n'arrive pas à choisir le premier élément avec class="red" en utilisant 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 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 classe red?


700
2018-04-26 22:51


origine


Réponses:


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

Les sélecteurs de niveau 3 introduisent un :first-of-type pseudo-classe, qui représente le premier élément parmi les frères et sœurs 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 ne regarde pas d'autres conditions ou attributs. En HTML, le type d'élément est représenté par le nom du tag. Dans la question, ce type est p.

Malheureusement, il n'y a pas de similaire :first-of-class pseudo-classe pour faire correspondre le premier élément enfant d'une classe donnée. Une solution de contournement Lea Verou et je suis venu avec pour cela (quoique totalement indépendant) est d'appliquer d'abord vos styles souhaités à tout 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 "défaire" les styles pour les éléments avec la classe viens après le premier, en utilisant le combinateur général de fratrie ~ dans une règle dominante:

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

Maintenant seulement le premier élément avec class="red" aura une frontière.

Voici une illustration de la façon dont les règles sont appliquées:

<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, donc c'est sauté.

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

  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é d'au moins un autre élément avec la classe red. Ainsi, les deux règles sont appliquées, et la seconde border La déclaration remplace la première, la "détruisant", pour ainsi dire.

En prime, bien qu'il ait été introduit dans Selectors 3, le combinateur général est en réalité plutôt bien supporté par IE7 et plus récent, contrairement à :first-of-type et :nth-of-type() qui sont uniquement pris en charge par IE9. Si vous avez besoin d'un bon support de navigateur, vous avez de la chance.

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

  • Vous pouvez l'utiliser 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 (encore une fois, 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'attribut ou tout autre sélecteur simple au lieu de classes.

  • Vous pouvez également combiner cette technique dominante 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 aurez besoin de savoir à l'avance quels seront les styles par défaut pour vos autres éléments frères afin de pouvoir remplacer la première règle. En outre, puisque cela implique des règles de chevauchement dans CSS, vous ne pouvez pas obtenir la même chose avec un seul sélecteur pour une utilisation avec le API de sélection, ou SéléniumLes localisateurs CSS.

Il convient de mentionner que Selectors 4 introduit une extension à la :nth-child() notation (à l'origine une pseudo-classe entièrement nouvelle appelée :nth-match()), ce 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'y a pas assez d'implémentations interopérables pour être utilisable sur les sites de production. J'espère que cela va bientôt changer. En attendant, la solution de contournement que j'ai suggéré 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'y a pas de pseudo-classe ni même de solution CSS générique pour le nième match d'un sélecteur complexe à travers le document entier - L'existence d'une solution dépend fortement de la structure du document. jQuery fournit :eq(), :first, :last et plus à cet effet, mais notez encore que ils fonctionnent très différemment de :nth-child() et al. En utilisant l'API Selectors, vous pouvez soit utiliser document.querySelector() pour obtenir le premier match:

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

Ou utiliser document.querySelectorAll() avec un indexeur pour choisir n'importe quelle correspondance spécifique:

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

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

Par exemple, si vous vouliez seulement sélectionner 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 tous les deux sera assorti par le sélecteur.

Quand le premier élément d'une certaine classe est aussi le premier de son type, la pseudo-classe va fonctionner, mais Cela n'arrive que par coïncidence. Ce comportement est démontré dans la réponse de Philip. Le moment où vous collerez 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>

Appliquer une règle avec .red:first-of-type va fonctionner, mais une fois que vous en ajoutez un 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 .red élément est maintenant le seconde  p élément.


1142
2017-12-16 19:21



le :first-child Le sélecteur est destiné, comme son nom l'indique, à sélectionner le premier enfant d'une balise parent. Les enfants doivent être intégrés dans la même balise parent. Votre exemple exact fonctionnera (juste essayé ici):

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

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

Notez également que ceci ne s'applique pas seulement à la première balise de ce type dans le document entier, mais à chaque fois qu'un nouveau parent l'entoure, 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 sera rouge alors.

Mettre à jour:

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

<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, donc tous les navigateurs ne le reconnaîtront pas (par exemple IE8 ou plus ancien).


304
2018-04-26 22:58



La bonne réponse est:

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

Partie I: Si l'élément est premier à son parent et a la classe "rouge", il doit avoir une bordure.
Partie II: Si l'élément ".red" n'est pas le premier à son parent, mais suit immédiatement un élément sans classe ".red", il doit également mériter l'honneur de ladite frontière.

Fiddle ou ça 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éfinit et écrase inutilement les styles
(en particulier un problème où il hériterait autrement d'une frontière différente - vous ne voulez pas déclarer autre à border: aucun)

MODIFIER: Dans le cas où vous avez "rouge" suivant non-rouge plusieurs fois, chaque "premier" rouge obtiendra la frontière. Pour éviter cela, il faudrait utiliser la réponse de BoltClock. Voir violon


58
2017-11-08 11:15



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


13
2018-01-13 00:57



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

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

8
2018-04-26 23:04



Puisque les autres réponses couvrent ce qui est faux avec ça, je vais essayer l'autre moitié, comment y remédier. Malheureusement, je ne sais pas si vous avez un CSS seulement solution ici, au moins pas que je puisse penser à. Il y a d'autres options cependant ....

  1. Attribuer un first classer à l'élément lorsque vous le générez, comme ceci:

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

    CSS:

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

    Ce CSS ne correspond qu'aux éléments avec tous les deux  first et red Des classes.

  2. Sinon, faites de même en JavaScript, par exemple voici ce que jQuery utiliserait pour cela, en utilisant le même CSS que ci-dessus:

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

6
2018-04-26 23:13



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

Cela va sélectionner maison de classe, puis l'élément envergure et enfin tout éléments .red qui sont placés immédiatement après les éléments span.

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


5
2018-01-21 11:49



Vous pouvez changer votre code pour quelque chose comme ça pour le faire fonctionner

<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 à propos de ça.


3
2017-10-14 10:15



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
2018-06-27 20:25