Puis-je combiner: nth-child () ou: nth-of-type () avec un sélecteur arbitraire?


117

Existe-t-il un moyen de sélectionner chaque nième enfant qui correspond (ou ne correspond pas) à un sélecteur arbitraire ? Par exemple, je souhaite sélectionner chaque ligne de tableau impaire, mais dans un sous-ensemble de lignes:

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>

Mais :nth-child()semble juste compter tous les tréléments indépendamment du fait qu'ils soient ou non de la classe "row", donc je me retrouve avec l' élément même "row" au lieu des deux que je recherche. La même chose se produit avec :nth-of-type().

Quelqu'un peut-il expliquer pourquoi?

Réponses:


144

C'est un problème très courant qui survient en raison d'un malentendu sur la façon :nth-child()et le :nth-of-type()travail. Malheureusement, il n'existe actuellement aucune solution basée sur un sélecteur, car Selectors ne fournit pas de moyen de faire correspondre le nième enfant qui correspond à un sélecteur arbitraire basé sur un modèle tel que les numéros impairs, pairs ou n'importe an+ba != 1et b != 0. Cela va au-delà des sélecteurs de classe, aux sélecteurs d'attributs, aux négations et aux combinaisons plus complexes de sélecteurs simples.

La :nth-child()pseudo-classe compte les éléments parmi tous leurs frères et sœurs sous le même parent. Il ne compte pas uniquement les frères et sœurs qui correspondent au reste du sélecteur. De même, la :nth-of-type()pseudo-classe compte les frères et sœurs partageant le même type d'élément, qui fait référence au nom de la balise en HTML, et non au reste du sélecteur.

Cela signifie également que si tous les enfants du même parent sont du même type d'élément, par exemple dans le cas d'un corps de tableau dont les seuls enfants sont des tréléments ou d'un élément de liste dont les seuls enfants sont des liéléments, alors :nth-child()et :nth-of-type()se comportera de manière identique, c'est-à-dire pour chaque valeur de an+b, :nth-child(an+b)et :nth-of-type(an+b)correspondra au même ensemble d'éléments.

En fait, tous les sélecteurs simples dans un sélecteur composé donné, y compris les pseudo-classes telles que :nth-child()et :not(), fonctionnent indépendamment les uns des autres, plutôt que de regarder le sous - ensemble d'éléments qui correspondent au reste du sélecteur.

Cela implique également qu'il n'y a pas de notion d'ordre parmi les sélecteurs simples au sein de chaque sélecteur composé individuel 1 , ce qui signifie par exemple que les deux sélecteurs suivants sont équivalents:

table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row

Traduits en anglais, ils signifient tous les deux:

Sélectionnez n'importe quel trélément qui correspond à toutes les conditions indépendantes suivantes:

  • c'est un enfant impaire de son parent;
  • il a la classe "row"; et
  • c'est un descendant d'un tableélément qui a la classe "myClass".

(vous remarquerez mon utilisation d'une liste non ordonnée ici, juste pour ramener le point à la maison)

Comme il n'y a actuellement pas de solution CSS pure, vous devrez utiliser un script pour filtrer les éléments et appliquer des styles ou des noms de classes supplémentaires en conséquence. Par exemple, ce qui suit est une solution de contournement courante utilisant jQuery (en supposant qu'il n'y a qu'un seul groupe de lignes rempli d' tréléments dans le tableau):

$('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');
});

Avec le CSS correspondant:

table.myClass tr.row.odd {
  ...
}

Si vous utilisez des outils de test automatisés tels que Selenium ou que vous traitez du HTML avec des outils tels que lxml, bon nombre de ces outils permettent à XPath comme alternative:

//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]

D'autres solutions utilisant différentes technologies sont laissées comme exercice au lecteur; ceci n'est qu'un bref exemple artificiel à titre d'illustration.


Pour ce que ça vaut, il y a une proposition pour une extension de la :nth-child()notation à ajouter au niveau 4 des sélecteurs dans le but spécifique de sélectionner chaque nième enfant correspondant à un sélecteur donné. 2

Le sélecteur par lequel filtrer les correspondances est fourni comme argument de :nth-child(), encore une fois en raison de la façon dont les sélecteurs fonctionnent indépendamment les uns des autres dans une séquence dictée par la syntaxe de sélecteur existante. Donc, dans votre cas, cela ressemblerait à ceci:

table.myClass tr:nth-child(odd of .row)

(Un lecteur astucieux constatera tout de suite que cela devrait être :nth-child(odd of tr.row)au contraire, puisque les sélecteurs simples tret :nth-child()fonctionnent indépendamment les uns des autres aussi bien. Ceci est l' un des problèmes avec les pseudo-classes fonctionnelles qui acceptent sélecteurs, une boîte de Pandore que je plutôt pas ouvert au milieu de cette réponse. Au lieu de cela, je vais partir avec l'hypothèse que la plupart des sites n'auront pas d'autres éléments que des tréléments en tant que frères et sœurs les uns des autres dans un corps de tableau, ce qui rendrait l'une ou l'autre des options fonctionnellement équivalentes.)

Bien sûr, étant une toute nouvelle proposition dans une toute nouvelle spécification, cela ne sera probablement pas mis en œuvre avant quelques années. En attendant, vous devrez vous en tenir à l'utilisation d'un script, comme ci-dessus.


1 Si vous spécifiez un type ou un sélecteur universel, il doit venir en premier. Cependant, cela ne change pas fondamentalement le fonctionnement des sélecteurs; ce n'est rien de plus qu'une bizarrerie syntaxique.

2 Cela a été proposé à l'origine car :nth-match(), cependant, parce qu'il ne compte toujours un élément que par rapport à ses frères et sœurs, et non à tous les autres éléments qui correspondent au sélecteur donné, il a depuis été réorienté depuis 2014 comme une extension de l'existant :nth-child().


3
"(vous remarquerez mon utilisation d'une liste non ordonnée ici, juste pour faire ressortir le point)" J'aurais aimé que plus de gens réfléchissent à leur utilisation des balles ordonnées vs non ordonnées. Merci pour votre réponse.
The Red Pea

1
@The Red Pea: Un de mes plus gros bêtes HTML: "Dans l'ordre du plus haut / du plus bas au plus bas / du plus élevé:" suivi d'une liste non ordonnée. Je veux dire allez, sérieusement?
BoltClock

6

Pas vraiment..

citation de la documentation

La :nth-childpseudo-classe correspond à un élément qui a un frère + b-1 avant lui dans l'arborescence du document , pour une valeur positive ou zéro donnée pour n, et a un élément parent.

C'est un sélecteur en soi et ne se combine pas avec les classes. Dans votre règle, il suffit de satisfaire les deux sélecteurs en même temps, de sorte qu'il affichera les :nth-child(even)lignes de la table si elles ont également la .rowclasse.


0

nth-of-typefonctionne selon l'index du même type d'élément mais nth-childfonctionne uniquement selon l'index quel que soit le type d'éléments frères.

Par exemple

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

Supposons que dans le html ci-dessus, nous voulons masquer tous les éléments ayant la classe rest.

Dans ce cas nth-childet nth-of-typefonctionnera exactement de la même manière que tous les éléments sont du même type que <div>css devrait être

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

OU

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

Maintenant, vous devez vous demander quelle est la différence entre nth-childet c'est nth-of-typedonc la différence

Supposons que le html soit

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

Dans le html ci-dessus, le type d' .restélément est différent des autres .restsont des paragraphes et les autres sont div donc dans ce cas, si vous utilisez, nth-childvous devez écrire comme ça

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

mais si vous utilisez le nième de type, css peut être ceci

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

Comme le type d' .restélément est <p>, voici la nth-of-typedétection du type de .rest, puis il a appliqué le CSS sur le 1er, 2e, 3e, 4e, 5e élément de <p>.


Dans quelle mesure cela est-il utile pour les <tr>balises?
Alexis Wilke

0

Vous pourrez peut-être le faire avec xpath. quelque chose comme ça //tr[contains(@class, 'row') and position() mod 2 = 0]pourrait marcher. Il existe d'autres questions SO développant les détails sur la manière de faire correspondre les classes plus précisément.


0

Voici ta réponse

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

Toutes les questions concernant l'utilisation de nth-child et le saut de balises cachées semblent rediriger comme dupes de celui-ci, je vais donc laisser ceci ici. Je suis tombé sur ce blog https://blog.blackbam.at/2015/04/09/css-nth-child-selector-ignore-hidden-element/ qui utilise une approche css intelligente pour que nth-child ignore les éléments cachés, comme suit:

Le CSS suivant ajoute une marge droite à chaque deuxième élément visible, quel que soit l'élément ayant 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;
}

J'espère que cela aidera quelqu'un qui suit la piste du dupe pour les questions d'ignorer les éléments cachés!


1
Je voudrais voter pour cela, mais il faut une démo fonctionnelle.
Moob le

Je me souviens que ce n'était pas aussi robuste qu'il y paraissait au départ - j'irais maintenant avec le commentaire le plus voté, ce n'est pas possible.
IrishDubGuy

0

SI vous avez la même classe parent pour tous les sélecteurs, vous utilisez cette classe document.querySelector("main .box-value:nth-child(3) select.priorityOption"); car dans ce cas document.querySelector("main .box-value select.priorityOption:nth-child(3)");ne fonctionne pas. Merci

<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>
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.